dtoi4539「TJOI / HEOI2016」序列

题意:

     玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化。现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可。每种变化最多只有一个值发生变化

题解:

     设Max[i]为a[i]可能变成的最大值,Min[i]为a[i]可能变成的最小值(Max[i]和Min[i]均包括a[i]本身)。那么i,j(i<j)连在一起的条件可以很容易得出:即a[i]<=Min[j]且Max[i]<=a[j]。很好理解,如果i变了,那么考虑极端情况,变成最大值也要满足条件,如果j变了,那么同样考虑极端情况,变成最小值也要满足条件。

     这样我们就可以dp了,f[i]表示以i结尾的最长合法序列,那么f[i]=f[j]+1(j满足上述条件)。这实际上是一个三维偏序,所以可以使用树套树维护,外层为a[i],内层为Max[i],使用树状数组套线段树维护即可解决问题。

#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int INF=100000;
int n,m,a[100002],Max[100002],Min[100002],rt[100002],cnt,f[100002],ans;
typedef struct{
    int ls,rs,Max;
}P;
P p[10000002];
void gengxin(int root,int begin,int end,int wz,int z){
    if (begin>wz || end<wz)return;
    if (begin==end)
    {
        p[root].Max=max(p[root].Max,z);
        return;
    }
    int mid=(begin+end)/2;
    if (wz<=mid)
    {
        if (!p[root].ls)p[root].ls=++cnt;
        gengxin(p[root].ls,begin,mid,wz,z);
    }
    else
    {
        if (!p[root].rs)p[root].rs=++cnt;
        gengxin(p[root].rs,mid+1,end,wz,z);
    }
    p[root].Max=max(p[p[root].ls].Max,p[p[root].rs].Max);
}
int chaxun(int root,int begin,int end,int begin2,int end2){
    if (!root || begin>end2 || end<begin2)return 0;
    if (begin>=begin2 && end<=end2)return p[root].Max;
    int mid=(begin+end)/2;
    return max(chaxun(p[root].ls,begin,mid,begin2,end2),chaxun(p[root].rs,mid+1,end,begin2,end2));
}
int getans(int x,int y){
    int ans=0;
    for (;x>=1;x-=(x&-x))ans=max(ans,chaxun(rt[x],1,INF,1,y));
    return ans;
}
void upd(int x,int y,int z){
    for (;x<=INF;x+=(x&-x))
    {
        if (!rt[x])rt[x]=++cnt;
        gengxin(rt[x],1,INF,y,z);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        Max[i]=Min[i]=a[i];
    }
    for (int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        Max[x]=max(Max[x],y);
        Min[x]=min(Min[x],y); 
    }
    for (int i=1;i<=n;i++)
    {
        f[i]=getans(Min[i],a[i])+1;
        upd(a[i],Max[i],f[i]);
        ans=max(ans,f[i]);
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2020-01-30 23:23  1124828077ccj  阅读(145)  评论(0编辑  收藏  举报