题目

佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他。玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化。

现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可。

注意:每种变化最多只有一个值发生变化。

在样例输入1中,所有的变化是

1 2 3
2 2 3
1 3 3
1 1 3
1 2 4

选择子序列为原序列,即在任意一种变化中均为不降子序列在样例输入2中,所有的变化是:

3 3 3

3 2 3

选择子序列为第一个元素和第三个元素,或者第二个元素和第三个元素,均可满足要求。

思路

显然的dp

dp[i]表示到第i个元素的时候,最优情况。

如果dp[i]可以有dp[j]转移而来,那么j需要满足以下两个条件:

  1. \(a[j]<=mi[i]\)
  2. \(mx[j]<=a[i]\)

然后考虑CDQ分治优化dp:

显然上面的转移是二维的,所以只要分别用排序和树状数组消维就行了。

代码

#include<bits/stdc++.h>
#define M 100005
using namespace std; 
int n,m;
struct node{
    int s,mi,mx,ans,id;
}A[M];
bool cmps(node a,node b){return a.s<b.s;}
bool cmpmi(node a,node b){return a.mi<b.mi;}
bool cmp(node a,node b){return a.id<b.id;}
struct BIT{
    int C[M];
    void add(int x,int d){
        x++;
        while(x<=M+1){
            C[x]=max(C[x],d);
            x+=(x&-x);
        }
    }
    int sum(int x){
        x++;int s=0;
        while(x){
            s=max(s,C[x]);
            x-=(x&-x);
        }
        return s;
    }
    void clear(int x){
        x++;
        while(x<=M+1){
            C[x]=0;
            x+=(x&-x);
        }
    }
}T;
void CDQ(int l,int r){
    if(l==r)return;
    int mid=(l+r)>>1;
    CDQ(l,mid);sort(A+mid+1,A+r+1,cmpmi);
    for(int i=l,j=mid+1;j<=r;j++){
        while(i<=mid&&A[i].s<=A[j].mi){
            T.add(A[i].mx,A[i].ans);i++;
        }
        A[j].ans=max(A[j].ans,T.sum(A[j].s)+1);
    }
    sort(A+mid+1,A+r+1,cmp);
    for(int i=l;i<=mid;i++)T.clear(A[i].mx);
    CDQ(mid+1,r);
    sort(A+l,A+r+1,cmps);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)A[i].mi=1e9,A[i].mx=-1e9,A[i].ans=1;
    for(int i=1,x;i<=n;i++)scanf("%d",&x),A[i].s=x,A[i].mi=min(A[i].mi,x),A[i].mx=max(A[i].mx,x),A[i].id=i;
    for(int i=1,x,y;i<=m;i++){
        scanf("%d%d",&x,&y);
        A[x].mx=max(A[x].mx,y);
        A[x].mi=min(A[x].mi,y);
    }
    CDQ(1,n);
    int ans=0;
    for(int i=1;i<=n;i++)ans=max(ans,A[i].ans); 
    printf("%d\n",ans); 
    return 0;
}