2020牛客国庆集训派对day8 好题整理

B

C

pro:
给出一个凸多边形
和它的一个三角剖分
在这种无向图上查询q次最短路

sol:
分治+bfs
每次选择一条边(a,b)进行分治
对于跨越这条边的询问(x,y)
一定会经过a,b中的一个
分别以a,b为起点计算最短路
然后分治块内部查询递归下去即可
写法的话考虑每次对所有节点重新标号进行分治

F

pro:
在一面长度为n的墙的基础上加石头
第i个位置可以加石头当且仅当当前i-1和i+1的高度都>=i的高度
询问加<=m块石头最多可以是这面墙的最高点多高

sol:
考虑枚举最高点
然后计算该点高度是否可以达到k
这个可以二分
然后发现想让i达到k
i-1和i+1就要k-1
i-2和i+2就要k-2
......
左边需要找到一个最大的j满足(k-(i-j)<=aj)
化简后为(k-i<=aj-j)
右边需要找到一个最小的j满足(k-(j-i)<=aj)
化简后为(k+i<=aj+j)
也就是变成了一个区间lower_bound问题
这个问题显然可以一个log解决
我这里用了线段树区间二分的方法
二分+rmq也可以
然后这样做的总复杂度就是(O(nlog^2n))
似乎有一个log的做法,由于博主Creed_太菜了,并不是很会

K

pro:从0开始依次画n条线,每次从(X_{i-1})画到(X_i)
现在要求改变一些(X_i),((X_i)始终>0)使得这些线不存在相交的情况
问最多有多少个不改变

画一张(X_i)为纵坐标,i为横坐标的路径折线图

发现只能保留一个单增子序列和一个单减子序列

而且还不能相交

那就先dp出来然后
排个序扫一下就行了

#include<bits/stdc++.h>
#define N 550000
#define eps 1e-7
#define inf 1e9+7
#define db double
#define ll long long
#define ldb long double
#define ull unsigned long long
using namespace std;
inline int read()
{
	char ch=0;
	int x=0,flag=1;
	while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
	return x*flag;
}
struct Segment_Tree
{
	#define lson o<<1
	#define rson o<<1|1
	#define mid ((l+r)>>1)
	int f[N*4],g[N*4];
	inline void pushup(int o)
	{
		f[o]=max(f[lson],f[rson]);
		g[o]=max(g[lson],g[rson]);
	}
	void optset(int o,int l,int r,int q,int x,int y)
	{
		if(l==r){f[o]=x;g[o]=y;return;}
		if(q<=mid)optset(lson,l,mid,q,x,y);
		if(q>mid)optset(rson,mid+1,r,q,x,y);
		pushup(o);
	}
	int queryf(int o,int l,int r,int ql,int qr)
	{
		if(ql<=l&&r<=qr)return f[o];
		int ans=0;
		if(ql<=mid)ans=max(ans,queryf(lson,l,mid,ql,qr));
		if(qr>mid)ans=max(ans,queryf(rson,mid+1,r,ql,qr));
		return ans;
	}
	int queryg(int o,int l,int r,int ql,int qr)
	{
		if(ql<=l&&r<=qr)return g[o];
		int ans=0;
		if(ql<=mid)ans=max(ans,queryg(lson,l,mid,ql,qr));
		if(qr>mid)ans=max(ans,queryg(rson,mid+1,r,ql,qr));
		return ans;
	}
}T;
struct node{int x,a,b;}p[N];
bool cmp(node a,node b){return a.x<b.x;}
int h[N];
int main()
{
	int n=read(),ans=0;
	for(int i=1;i<=n;i++)h[i]=read();
	for(int i=1;i<=n;i++)
	{
		p[i].x=h[i];
		p[i].a=T.queryf(1,1,n,h[i],n)+1;
		p[i].b=T.queryg(1,1,n,1,h[i])+1;
		T.optset(1,1,n,h[i],p[i].a,p[i].b);
	}
	sort(p+1,p+n+1,cmp);
	for(int i=1,k=0;i<=n;i++)ans=max(ans,p[i].a+k),k=max(k,p[i].b);
	printf("%d",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/Creed-qwq/p/13789867.html