P4093-[HEOI2016/TJOI2016]序列【CDQ分治,树状数组】

正题

题目链接:https://www.luogu.com.cn/problem/P4093


题目大意

n n n个数字,每次有一个数字可能和原序列不同,但最多只有一个不同。

求所有情况下都满足的最长不降子序列


解题思路

定义 m a x i max_i maxi表示位置 i i i的最大数, m i n i min_i mini表示位置 i i i的最小数。

然后有转移方程 f i = m a x { f j } + 1 ( a i ≥ m a x j , m i n i ≥ a j ) f_i=max\{f_j\}+1(a_i\geq max_j,min_i\geq a_j) fi=max{fj}+1(aimaxj,miniaj)

可以发现这是一个三维偏序,用cdq分治+树状数组即可。


c o d e code code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define lowbit(x) (x&-x)
using namespace std;
const int N=1e5+10;
int n,m,a[N],b[N],s[N];
int t[N],p[N],f[N],ans;
bool cmp1(int x,int y)
{return b[x]<b[y];}
bool cmp2(int x,int y)
{return a[x]<a[y];}
void Change(int x,int val){
	while(x<=n){
		t[x]=max(t[x],val);
		x+=lowbit(x);
	}
	return;
}
void Clear(int x){
	while(x<=n){
		t[x]=0;
		x+=lowbit(x);
	}
	return;
}
int Ask(int x){
	int ans=0;
	while(x){
		ans=max(ans,t[x]);
		x-=lowbit(x);
	}
	return ans;
}
void cdq(int l,int r){
	if(l==r){
		f[l]=max(f[l],1);
		return;
	}
	int mid=(l+r)>>1;
	cdq(l,mid);
	for(int i=l;i<=r;i++)
		p[i]=i;
	sort(p+l,p+mid+1,cmp1);
	sort(p+mid+1,p+r+1,cmp2);
	int k=l;
	for(int i=mid+1;i<=r;i++){
		while(k<=mid&&b[p[k]]<=a[p[i]])
			Change(a[p[k]],f[p[k]]),k++;
		f[p[i]]=max(f[p[i]],Ask(s[p[i]])+1);
	}
	for(int i=l;i<=mid;i++)
		Clear(a[i]);
	cdq(mid+1,r);
	return;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]),b[i]=s[i]=a[i];
	for(int i=1;i<=m;i++){
		int x,y;scanf("%d%d",&x,&y);
		b[x]=max(b[x],y);s[x]=min(s[x],y);
	}
	cdq(1,n);
	for(int i=1;i<=n;i++)
		ans=max(ans,f[i]);
	printf("%d",ans);
}
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页