• [BZOJ4553][HEOI2016]序列 CDQ分治


    4553: [Tjoi2016&Heoi2016]序列

    Time Limit: 20 Sec  Memory Limit: 128 MB

    Description

     佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他。玩具上有一个数列,数列中某些项的值

    可能会变化,但同一个时刻最多只有一个值发生变化。现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你
    ,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可
    。注意:每种变化最多只有一个值发生变化。在样例输入1中,所有的变化是:
    1 2 3
    2 2 3
    1 3 3
    1 1 31 2 4
    选择子序列为原序列,即在任意一种变化中均为不降子序列在样例输入2中,所有的变化是:3 3 33 2 3选择子序列
    为第一个元素和第三个元素,或者第二个元素和第三个元素,均可满足要求

    Input

     输入的第一行有两个正整数n, m,分别表示序列的长度和变化的个数。接下来一行有n个数,表示这个数列原始的

    状态。接下来m行,每行有2个数x, y,表示数列的第x项可以变化成y这个值。1 <= x <= n。所有数字均为正整数
    ,且小于等于100,000

    Output

     输出一个整数,表示对应的答案

    Sample Input

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

    Sample Output

    3
     
    题解:
    我们来分析一下这道题让我们干什么:
    我们知道了一个序列,其中每一个元素都可能变化,
    我们设他的原始值为a[i],最大值为maxv[i],最小值为minv[i],
    再设f[i]为以i为结尾的最长符合要求子序列,显然这可以用一个dp来解决:对于f[i],有
      f[i]=max{f[j]}+1
    而对j的要求,由于同时只有一个元素发生变化,我们就要求满足
      j<i&&maxv[j]<=a[i]&&a[j]<=minv[i]
    我们发现,这好像长得“很像”一个三维偏序问题。
    如果我们用树套树来解决的话,也不是不可以(详见勇士的战斗记录:BZOJ4553: [Tjoi2016&Heoi2016]序列 树套树优化DP
    但是为什么我们不用更简单的做法来解决呢?
    显然,这个东西是可以用cdq分治来解决的
    我们对于区间[l,r],如果这个元素i在mi前面,我们就用(maxv[i],a[i])作为他的权值;否则,就用(a[i],minv[i])来作为他的权值。
    这样,就可以实现上面的想法了:用前面来更新后面。这也是本题的关键。
    想到了这一点,代码实现就很简单了。代码见下:
     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 const int N=300000;
     7 int n,m,bit[N+100],f[N+100];
     8 struct num{int val,maxv,minv;}x[N+100];
     9 struct cdq{int x,y,id;}a[N+100];
    10 inline int lowbit(int a){return a&(-a);}
    11 inline bool mt(const cdq &a,const cdq &b)
    12 {return (a.x==b.x)?a.id<b.id:a.x<b.x;}
    13 inline void add(int i,int val)
    14 {
    15     while(i<=N)
    16     {
    17         bit[i]=(val==0)?0:max(bit[i],val);
    18         i+=lowbit(i);
    19     }
    20 }
    21 inline int sum(int i)
    22 {
    23     int ret=0;
    24     while(i)
    25         ret=max(ret,bit[i]),i-=lowbit(i);
    26     return ret;
    27 }
    28 void cdq(int l,int r)
    29 {
    30     if(l==r){f[l]=max(f[l],1);return;}
    31     int mi=(l+r)>>1;
    32     cdq(l,mi);
    33     for(int i=l;i<=r;i++)
    34     {
    35         if(i<=mi)a[i].x=x[i].val,a[i].y=x[i].maxv;
    36         else a[i].x=x[i].minv,a[i].y=x[i].val;
    37         a[i].id=i;
    38     }
    39     sort(a+l,a+r+1,mt);
    40     for(int i=l;i<=r;i++)
    41     {
    42         if(a[i].id<=mi)add(a[i].y,f[a[i].id]);
    43         else f[a[i].id]=max(sum(a[i].y)+1,f[a[i].id]);
    44     }
    45     for(int i=l;i<=r;i++)add(a[i].y,0);
    46     cdq(mi+1,r);
    47 }
    48 int main()
    49 {
    50     scanf("%d%d",&n,&m);int u,v,ans=0;
    51     for(int i=1;i<=n;i++)
    52         scanf("%d",&x[i].val),x[i].minv=x[i].maxv=x[i].val;
    53     while(m--)
    54     {
    55         scanf("%d%d",&u,&v);
    56         x[u].maxv=max(x[u].maxv,v);
    57         x[u].minv=min(x[u].minv,v);
    58     }
    59     cdq(1,n);
    60     for(int i=1;i<=n;i++)ans=max(ans,f[i]);
    61     printf("%d
    ",ans);
    62 }
  • 相关阅读:
    一百个人眼中的一百种爱情
    苏迪曼杯羽毛球赛
    站点地图
    魔兽争霸微操教学(精华篇)
    (转)为winform程序注册闪屏(等待窗体)
    (转)Blend操作入门: 别站在门外偷看,快进来吧!
    (转)Asp.Net MVC的路由机制
    (转)VS2010在制作Setup项目的时候没有.NET 2.0的先决条件发行包
    (转)打造自己的LINQ Provider(上):Expression Tree揭秘
    (转)C#中的委托,匿名方法和Lambda表达式
  • 原文地址:https://www.cnblogs.com/LadyLex/p/7221446.html
Copyright © 2020-2023  润新知