• UESTC 360(1425) another LCIS


    这道题是CD老OJ上面的一道题,现在在新OJ上的题号是360,开始在VJ上做的提交一直RE(囧)。后来才知道OJ移位了。

    这道题是一个简单的成段更新+区间合并的线段树的题,1A还让我小激动了一下

    这道题的大概意思是有两种操作,一种是成段地增加一个值,另外一种是询问从l到r这段区间内的最长递增子序列

    首先先分析一下,如果某一段的值成段地增加一个量,那么该区间内的数的相对大小是不变的,因此递增子序列的长度是不会改变的

    是要分析对于结果有影响的信息与值:一是每个子区间中的最值,二是有可能在两个区间合并之后的两个区间的中间的两段成为新的最值,因此我们需要判断中间的两个值是否可以合并,从何得知:我们需要在运算过程中分别记录下左端点的值和右端点的值,来判断是否可以合并。因此在每个节点增设两个值lv,rv。

    还有一个问题就是在查询过程中,可能会存在查询的范围R-mid比lsum[rt<<1|1]小(mid-L+1比rsum[rt<<1]小),因此用比较取较小值相加就OK;额

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int SIZEN=100005;
     6 int sum[SIZEN<<2],lsum[SIZEN<<2],rsum[SIZEN<<2];
     7 int lv[SIZEN<<2],rv[SIZEN<<2],add[SIZEN<<2];
     8 int a[SIZEN];
     9 void pushup(int len,int rt){
    10     int tmp;
    11     lsum[rt]=lsum[rt<<1];
    12     rsum[rt]=rsum[rt<<1|1];
    13     lv[rt]=lv[rt<<1];rv[rt]=rv[rt<<1|1];
    14     if(lsum[rt]==(len-(len>>1))&&rv[rt<<1]<lv[rt<<1|1]) lsum[rt]+=lsum[rt<<1|1];
    15     if(rsum[rt]==(len>>1)&&rv[rt<<1]<lv[rt<<1|1]) rsum[rt]+=rsum[rt<<1];
    16     tmp=rsum[rt<<1]+lsum[rt<<1|1];
    17     if(rv[rt<<1]<lv[rt<<1|1])
    18         sum[rt]=max(tmp,max(sum[rt<<1],sum[rt<<1|1]));
    19     else sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
    20 }
    21 void pushdown(int rt){
    22     if(add[rt]!=0){
    23         add[rt<<1]+=add[rt];
    24         add[rt<<1|1]+=add[rt];
    25         lv[rt<<1]+=add[rt];rv[rt<<1]+=add[rt];
    26         lv[rt<<1|1]+=add[rt];rv[rt<<1|1]+=add[rt];
    27         add[rt]=0;
    28     }
    29 }
    30 void update(int L,int R,int o,int l,int r,int rt){
    31     if(L<=l&&r<=R){
    32         add[rt]+=o;
    33         lv[rt]+=o;rv[rt]+=o;
    34         return;
    35     }
    36     pushdown(rt);
    37     int mid=(l+r)>>1;
    38     if(L<=mid) update(L,R,o,l,mid,rt<<1);
    39     if(mid+1<=R) update(L,R,o,mid+1,r,rt<<1|1);
    40     pushup(r-l+1,rt);
    41 }
    42 void build(int l,int r,int rt){
    43     add[rt]=0;
    44     if(l==r){
    45         sum[rt]=lsum[rt]=rsum[rt]=1;
    46         lv[rt]=rv[rt]=a[l];
    47         return;
    48     }
    49     int mid=(l+r)>>1;
    50     build(l,mid,rt<<1);
    51     build(mid+1,r,rt<<1|1);
    52     pushup(r-l+1,rt);
    53 }
    54 int query(int L,int R,int l,int r,int rt){
    55     if(L<=l&&r<=R){
    56         return sum[rt];
    57     }
    58     int mid=(l+r)>>1,r1,r2,r3;
    59     int len=r-l+1;
    60     r1=r2=r3=-1;
    61     pushdown(rt);
    62     if(L<=mid) r1=query(L,R,l,mid,rt<<1);
    63     if(mid+1<=R) r2=query(L,R,mid+1,r,rt<<1|1);
    64     if(rv[rt<<1]<lv[rt<<1|1]) r3=min(rsum[rt<<1],mid-L+1)+min(lsum[rt<<1|1],R-mid);
    65     return max(r1,max(r2,r3));
    66 }
    67 int main()
    68 {
    69     //freopen("data.in","r",stdin);
    70     int i,j,_;
    71     char c;
    72     int l,r,o;
    73     int n,q,txt=1;
    74     scanf("%d",&_);
    75     while(_--){
    76         printf("Case #%d:
    ",txt++);
    77         scanf("%d%d",&n,&q);
    78         for(i=1;i<=n;i++)
    79             scanf("%d",&a[i]);
    80         build(1,n,1);
    81         while(q--){
    82             scanf(" %c",&c);
    83             if(c=='a'){
    84                 scanf("%d%d%d",&l,&r,&o);
    85                 update(l,r,o,1,n,1);
    86             }
    87             else{
    88                 scanf("%d%d",&l,&r);
    89                 int ret=query(l,r,1,n,1);
    90                 printf("%d
    ",ret);
    91             }
    92         }
    93     }
    94     return 0;
    95 }
  • 相关阅读:
    linux 声音大小调整的命令
    Linux下cron的使用
    MySql中添加用户,新建数据库,用户授权,删除用户,修改密码
    yii 删除内容时增加ajax提示
    git 忽略权限
    yii CGridView colum 链接
    yii cgridview 对生成的数据进行分页
    yii cgridview 默认的筛选如何做成选择框
    db2 Reorgchk:重组检查,是否需要重组
    Linux 下文件
  • 原文地址:https://www.cnblogs.com/acalvin/p/3702368.html
Copyright © 2020-2023  润新知