[bzoj4553]序列

记第i个位置有三个属性:1.ai表示原来的值;2.bi表示变成最大的值;3.ci表示变成最小的值。那么对于如果i在j的前面,那么必然有:$ai\le cj$且$bi\le aj$,那么令f[i]表示以i为结尾的最长上升子序列,即对求max(f[j])满足j能在i的前面,用树套树维护即可

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 100005 
 4 #define mid (l+r>>1)
 5 int V,n,m,x,y,ans,a[N],b[N],c[N],ro[N*200],f[N*200],ls[N*200],rs[N*200];
 6 void update(int &k,int l,int r,int x,int y,int z){
 7     if (!k)k=++V;
 8     if (y)update(ro[k],1,N-5,y,0,z);
 9     if (l==r){
10         f[k]=max(f[k],z);
11         return;
12     }
13     if (x<=mid)update(ls[k],l,mid,x,y,z);
14     else update(rs[k],mid+1,r,x,y,z);
15     f[k]=max(f[ls[k]],f[rs[k]]);
16 }
17 int query(int k,int l,int r,int x,int y,int x2,int y2){
18     if ((!k)||(l>y)||(x>r))return 0;
19     if ((x<=l)&&(r<=y))
20         if (x2)return query(ro[k],1,N-5,x2,y2,0,0);
21         else return f[k];
22     return max(query(ls[k],l,mid,x,y,x2,y2),query(rs[k],mid+1,r,x,y,x2,y2));
23 }
24 int main(){
25     scanf("%d%d",&n,&m);
26     for(int i=1;i<=n;i++){
27         scanf("%d",&a[i]);
28         b[i]=c[i]=a[i];
29     }
30     for(int i=1;i<=m;i++){
31         scanf("%d%d",&x,&y);
32         b[x]=max(b[x],y);
33         c[x]=min(c[x],y);
34     }
35     update(x=0,1,N-5,a[1],b[1],1);
36     for(int i=2;i<=n;i++){
37         int s=query(1,1,N-5,1,c[i],1,a[i])+1;
38         update(x,1,N-5,a[i],b[i],s);
39         ans=max(ans,s);
40     }
41     printf("%d\n",ans);
42 }
View Code

猜你喜欢

转载自www.cnblogs.com/PYWBKTDA/p/11272801.html