标签:out stream long max gif play 注意 自己 最大
这道题的题意是求
j<i
aj<=a0[i]
a1[j]<=a[i]
这样的三维上升子序列
发现也是一道三维偏序问题,因此考虑用CDQ分治
对于第一位,我们按照惯例作为时间轴,但是这一次,查询要在前面,因为这里第一位是小于号,所以我们先查询再更改就不会弄到自己
我们将查询的权值设为a0[i],而修改的作为a[i],这样排序的时候就能知道把第二维排序掉了,当第二维相同,就是修改在前,因为这次可以查询相等的
对于第三维,使用树状数组,不同于之前的是,这里存的不是和,而是前面的最大值,不过用法是一样的
注意,清空树状数组的时候不能直接memset,因为这是O(N)的复杂度,而应该采用树状数组清空的方式,这样是log复杂度,所以这道题有双log,否则就超过复杂度了
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; typedef long long ll; const int N=1e5+10; const int mod=1e9+7; struct node{ int a,b,op,id; }q[2*N],q0[2*N]; int a[N],a1[N],a0[N]; int tr[N]; int f[N]; int lowbit(int x){ return x&-x; } void add(int x,int c,int op){ int i; for(i=x;i<=1e5;i+=lowbit(i)){ if(op==0) tr[i]=0;//清空树状数组 else{ tr[i]=max(tr[i],c); } } } int sum(int x){ int res=0; int i; for(i=x;i;i-=lowbit(i)){ res=max(res,tr[i]); } return res; } bool cmp(node a,node b){ if(a.b==b.b) return a.op<b.op; return a.b<b.b; } void solve(int l,int r){ if(l==r) return ; int mid=l+r>>1; solve(l,mid); sort(q+l,q+1+r,cmp); int i; for(i=l;i<=r;i++){ int id=q[i].id; if(q[i].a<=mid&&q[i].op==1) add(a1[id],f[id],1); if(q[i].a>=mid+1&&q[i].op==2) f[id]=max(f[id],sum(a[id])+1); } for(i=l;i<=r;i++){ int id=q[i].id; if(q[i].a<=mid&&q[i].op==1) add(a1[id],f[id],0); } for(i=l;i<=r;i++) q[i]=q0[i]; solve(mid+1,r); } int main(){ int n,m; cin>>n>>m; int i; for(i=1;i<=n;i++){ scanf("%d",&a[i]); a1[i]=a[i]; a0[i]=a[i]; } while(m--){ int u,v; cin>>u>>v; a1[u]=max(a1[u],v); a0[u]=min(a0[u],v); } for(i=1;i<=n;i++){ q[2*i-1]=node{2*i-1,a0[i],2,i}; q[2*i]=node{2*i,a[i],1,i}; } for(i=1;i<=2*n;i++) q0[i]=q[i]; for(i=1;i<=n;i++) f[i]=1; solve(1,2*n); int ans=0; for(i=1;i<=n;i++){ ans=max(ans,f[i]); } cout<<ans<<endl; }
P4093 [HEOI2016/TJOI2016]序列 (CDQ分治)
标签:out stream long max gif play 注意 自己 最大
原文地址:https://www.cnblogs.com/ctyakwf/p/12744458.html