码迷,mamicode.com
首页 > 其他好文 > 详细

dtoi4539「TJOI / HEOI2016」序列

时间:2020-01-31 01:10:34      阅读:88      评论:0      收藏:0      [点我收藏+]

标签:print   一起   upd   struct   names   strong   序列   ace   解决问题   

题意:

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

题解:

     设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;
}

dtoi4539「TJOI / HEOI2016」序列

标签:print   一起   upd   struct   names   strong   序列   ace   解决问题   

原文地址:https://www.cnblogs.com/1124828077ccj/p/12244344.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!