• BZOJ1500:[NOI2005]维修数列


    1500: [NOI2005]维修数列

    Time Limit: 10 Sec  Memory Limit: 64 MB
    Submit: 14486  Solved: 4723
    [Submit][Status][Discuss]

    Description

    Input

    输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
    第2行包含N个数字,描述初始时的数列。
    以下M行,每行一条命令,格式参见问题描述中的表格。
    任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
    插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。

    Output

    对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

    Sample Input

    9 8
    2 -6 3 5 1 -5 -3 6 3
    GET-SUM 5 4
    MAX-SUM
    INSERT 8 3 -5 7 2
    DELETE 12 1
    MAKE-SAME 3 3 2
    REVERSE 3 6
    GET-SUM 5 4
    MAX-SUM

    Sample Output

    -1
    10
    1
    10

    HINT

    思路{

      为何发现我的蛋碎了..........

      为何发现被维修的不是数列,而是我.........

      关键是最后一个操作!

      设l[x]为以当前节点所代表的区间左端点为起点的序列最大值,

      那么往上传的时候,由于以下标为键值l[x]=Max(l[ls],Sum[ls]+v[x]+l[rs]);

      同理更新r[x],Max[x]为一段区间内最大值,Max[x]在上传的过程中一路更新(很妙啊~~~)

      然后就轻巧地用嘴巴AC~~~~(调得想死.......)

      膜Hzwer的代码咯.

    }

    #include<bits/stdc++.h>
    #define RG register
    #define il inline 
    #define N 1000005
    #define rs (ch[x][1])
    #define ls (ch[x][0])
    using namespace std;
    int ch[N][2],fa[N],sum[N],l[N],r[N],sz[N],v[N],Max[N],rt,id[N],a[N],n,m,cnt;bool tag[N],rev[N];
    void up(int x){
       sz[x]=sz[ls]+sz[rs]+1;
       sum[x]=sum[rs]+sum[ls]+v[x];
       Max[x]=max(Max[rs],Max[ls]);
       Max[x]=max(Max[x],v[x]+r[ls]+l[rs]);
       l[x]=max(l[ls],sum[ls]+v[x]+l[rs]);
       r[x]=max(r[rs],sum[rs]+v[x]+r[ls]);
    }
    void down(int x){
      if(tag[x]){
        rev[x]=tag[x]=0;
        if(rs)v[rs]=v[x],sum[rs]=sz[rs]*v[x],tag[rs]=1;
        if(ls)v[ls]=v[x],sum[ls]=sz[ls]*v[x],tag[ls]=1;
        if(v[x]>=0){
          if(ls)l[ls]=r[ls]=Max[ls]=sum[ls];
          if(rs)l[rs]=r[rs]=Max[rs]=sum[rs];
        }else {
          if(ls)l[ls]=r[ls]=0,Max[ls]=v[x];
          if(rs)l[rs]=r[rs]=0,Max[rs]=v[x];
        }
      }if(rev[x])rev[x]^=1,rev[rs]^=1,rev[ls]^=1,swap(rs,ls),swap(l[rs],r[rs]),swap(l[ls],r[ls]);
    }
    void Rotate(int x,int &k){
      int y=fa[x],z=fa[y],l,r;if(z)down(z);down(y),down(x);
      l=ch[y][1]==x,r=l^1;
      if(y==k)k=x;
      else ch[z][ch[z][1]==y]=x;
      fa[x]=z,fa[y]=x,fa[ch[x][r]]=y;ch[y][l]=ch[x][r];
      ch[x][r]=y;
      up(y),up(x);
    }
    void Splay(int x,int &k){
      while(x!=k){
        int y=fa[x],z=fa[y];
        if(y!=k){
          if(ch[z][0]==y^ch[y][0]==x)Rotate(x,k);
          else Rotate(y,k);
        }Rotate(x,k);
      }
    }queue<int>que;
    int find(int x,int rnk){
      down(x);
      if(sz[ls]+1==rnk)return x;
      if(sz[ls]>=rnk)return find(ls,rnk);
      return find(rs,rnk-sz[ls]-1);
    }
    void clean(int x){
      if(!x)return;
      clean(rs),clean(ls),que.push(x);
      fa[x]=rs=ls=tag[x]=rev[x]=0;
    }
    int Split(int k,int tot){
      int x=find(rt,k),y=find(rt,k+tot+1);
      Splay(x,rt),Splay(y,ch[x][1]);
      return ch[y][0];
    }
    void Querysum(int k,int tot){
      int x=Split(k,tot);
      printf("%d
    ",sum[x]);
    }
    void Modify(int k,int tot,int val){
      int x=Split(k,tot),y=fa[x];
      v[x]=val;tag[x]=1;sum[x]=sz[x]*v[x];
      if(val>=0)l[x]=r[x]=Max[x]=sum[x];
      else l[x]=r[x]=0,Max[x]=v[x];
      up(y),up(fa[y]);
    }
    void rever(int k,int tot){
      int x=Split(k,tot),y=fa[x];
      if(!tag[x]){
        rev[x]^=1;swap(l[x],r[x]);
        up(y),up(fa[y]);
      }
    }
    void del(int k,int tot){
      int x=Split(k,tot),y=fa[x];
      clean(x);ch[y][0]=0;up(y),up(fa[y]);  
    }
    #define mid ((L+R)>>1)
    void build(int L,int R,int f){
      if(L>R)return;
      int x=id[mid],faa=id[f];
      if(L==R){
        sz[x]=1,sum[x]=a[L];
        tag[x]=0;
        if(a[L]>=0)l[x]=r[x]=Max[x]=a[L];
        else l[x]=r[x]=0,Max[x]=a[L];
      }else build(L,mid-1,mid),build(mid+1,R,mid);
      v[x]=a[mid],fa[x]=faa;up(x);
      ch[faa][f<=mid]=x;
    }
    void Insert(int k,int tot){
      for(int i=1;i<=tot;++i)scanf("%d",&a[i]);
      for(int i=1;i<=tot;++i)
        if(!que.empty())id[i]=que.front(),que.pop();
        else id[i]=++cnt;
      build(1,tot,0);int z=id[((1+tot)>>1)];
      int x=find(rt,k+1),y=find(rt,k+2);
      Splay(x,rt),Splay(y,ch[x][1]);
      fa[z]=y,ch[y][0]=z,up(y),up(x);
    }int k,tot;
    int main(){
      scanf("%d%d",&n,&m);Max[0]=a[1]=a[n+2]=-6666666;
      for(int i=1;i<=n;++i)scanf("%d",&a[i+1]);
      for(int i=1;i<=n+2;++i)id[i]=i;
      build(1,n+2,0);rt=(n+3)>>1,cnt=n+2;
      char s[10];
      for(int i=1;i<=m;++i){
        scanf("%s",s);
        if(s[0]=='I'){scanf("%d%d",&k,&tot),Insert(k,tot);}
        if(s[0]=='D'){scanf("%d%d",&k,&tot),del(k,tot);}
        if(s[0]=='M'&&s[2]=='K'){int c;scanf("%d%d%d",&k,&tot,&c),Modify(k,tot,c);}
        if(s[0]=='R'){scanf("%d%d",&k,&tot),rever(k,tot);}
        if(s[0]=='G'){scanf("%d%d",&k,&tot),Querysum(k,tot);}
        if(s[0]=='M'&&s[2]=='X'){printf("%d
    ",Max[rt]);}
      }
      return 0;
    }
    

      

  • 相关阅读:
    [LeetCode] 159. Longest Substring with At Most Two Distinct Characters 最多有两个不同字符的最长子串
    [LeetCode] 76. Minimum Window Substring 最小窗口子串
    window.scrollTo和window.scrollBy
    background-clip与background-origin
    page-break-before和page-break-after
    CSS counter计数器(content目录序号自动递增)详解
    移动端网页巧用 margin和padding 的百分比实现自适应
    监听屏幕旋转事件window. onorientationchange
    apple-touch-startup-image 制作iphone web应用程序的启动画面
    当把链接保存到手机桌面。设置图标 只在safari浏览器中有用
  • 原文地址:https://www.cnblogs.com/zzmmm/p/7261907.html
Copyright © 2020-2023  润新知