题目大意
有一个长度为n的序列,有一些位置的值有可能变化。
一次变化最多只会改变一个位置上的值,题目告诉了你可能发生的变化情况。
求在任意可能情况下都能满足非降的最长子序列长度。
DP
先弄出偏序关系,设mi[i]表示位置i可能出现的最小值,mx[i]就是最大值。
那么对于
j<i
,j与i可以在一个合法子序列中的条件是:
1、a[j]<=mi[i]
2、mx[j]<=a[i]
设f[i]表示以i结尾最长合法子序列长度,那么显然这个DP我们只会n^2的。
整体二分
现在,相当于有n个询问。
第i个询问要求你求解f[i]。
那么我们将n个询问整体二分。
solve(l,r)表示解决第l~r个询问。
显然我们可以先去解决第l~mid个询问(solve(l,mid))
接下来考虑左边对右边的影响,那么我们可以让左边根据a值排序,右边根据mi值排序,然后用一个指针,这样可以满足第一个偏序条件。
对于第二个条件,用线段树维护。
然后,就成功处理了右边部分的上一个是左边部分的情况,而右边部分也有可能上一个不在左边部分,递归处理即可(solve(mid+1,r))
于是复杂度n log^2 n解决本题。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100000+10,maxd=100000;
int tree[maxd*5];
bool bz[maxd*5];
int a[maxn],id[maxn],mi[maxn],mx[maxn],f[maxn];
int i,j,k,l,t,n,m,ans;
void mark(int p){
tree[p]=0;
bz[p]=1;
}
void down(int p){
if (bz[p]){
mark(p*2);
mark(p*2+1);
bz[p]=0;
}
}
void change(int p,int l,int r,int a,int b){
if (l==r){
tree[p]=max(tree[p],b);
return;
}
down(p);
int mid=(l+r)/2;
if (a<=mid) change(p*2,l,mid,a,b);else change(p*2+1,mid+1,r,a,b);
tree[p]=max(tree[p*2],tree[p*2+1]);
}
int query(int p,int l,int r,int a,int b){
if (l==a&&r==b) return tree[p];
down(p);
int mid=(l+r)/2;
if (b<=mid) return query(p*2,l,mid,a,b);
else if (a>mid) return query(p*2+1,mid+1,r,a,b);
else return max(query(p*2,l,mid,a,mid),query(p*2+1,mid+1,r,mid+1,b));
}
bool cmpa(int x,int y){
return a[x]<a[y];
}
bool cmpmi(int x,int y){
return mi[x]<mi[y];
}
void solve(int l,int r){
if (l==r){
f[l]=max(f[l],1);
return;
}
int mid=(l+r)/2;
solve(l,mid);
int i;
fo(i,l,r) id[i]=i;
sort(id+l,id+mid+1,cmpa);
sort(id+mid+1,id+r+1,cmpmi);
mark(1);
int j=l;
fo(i,mid+1,r){
while (j<=mid&&a[id[j]]<=mi[id[i]]){
change(1,1,maxd,mx[id[j]],f[id[j]]);
j++;
}
f[id[i]]=max(f[id[i]],query(1,1,maxd,1,a[id[i]])+1);
}
solve(mid+1,r);
}
int main(){
freopen("4553.in","r",stdin);freopen("4553.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,n) scanf("%d",&a[i]),mi[i]=mx[i]=a[i];
fo(i,1,m){
scanf("%d%d",&j,&k);
mi[j]=min(mi[j],k);
mx[j]=max(mx[j],k);
}
solve(1,n);
ans=0;
fo(i,1,n) ans=max(ans,f[i]);
printf("%d\n",ans);
}