zoukankan      html  css  js  c++  java
  • [NOI2005]维护数列

    输入格式

    输入文件的第 1 行包含两个数 N 和 M,N 表示初始时数列中数的个数,M 表示要进行的操作数目。 第 2 行包含 N 个数字,描述初始时的数列。 以下 M 行,每行一条命令,格式参见问题描述中的表格

    输出格式

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

    你可以认为在任何时刻,数列中至少有 1 个数。

    输入数据一定是正确的,即指定位置的数在数列中一定存在。

    100%的数据中,任何时刻数列中最多含有 500 000 个数。

    100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。

    100%的数据中,M ≤20 000,插入的数字总数不超过 4 000 000 。

    题解

    序列翻转基本操作

    区间最大子段和

    有了上面的铺垫,其实这些操作都可以解决了。

    以下的根不做特殊说明都指区间代表子树的根。

    只是有点小细节需要注意:

    插入时要先把插入序列建splay,不然一个一个插入会超时。建splay时需要特判叶子节点维护一些信息,对于lmax和rmax需要将val和0取max,因为在父亲节点更新lmax是可能为左区间+父亲节点本身,如果右区间lmax直接取val,就可能取不到这种情况,或许比较三种情况可以解决这个问题,但是很麻烦不是吗。

    删除的时候,把这段区间提取出来删除即可。不过因为空间原因需要回收节点编号,所以需要遍历这棵子树回收,用队列装编号。最多插入4e6个数,所以最多遍历4e6个点。

    区间覆盖的时候,提取区间后,在根打上覆盖标记,维护节点信息:注意如果val是负数最大子段和赋成val。

    翻转提取区间,在根打上翻转标记,将lmax和rmax交换

    求和提取区间输出根的sum即可。

    这道题的最大子段和是整个序列的,其实降低了一点难度,直接输出整颗splay的根的最大子段和即可。

    下传在find里面。

    建初始序列时要在收尾插入两个最小值,因为最大值在求最大子段和会有影响。

    还有对于0号节点的最大子段和赋最小值,因为一些没有儿子的点更新信息会用到。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int oo=1000000;
    const int maxn=500005;
    int n,m;
    int a[maxn],num,id[maxn],root;
    queue<int> q;
    struct Splay{
      int s[2],fa,size,tag,cover;//tag:当前节点是否需要交换儿子
      int val,sum,dat,lmax,rmax;
    }tr[maxn];
    
    template<class T>inline void read(T &x){
      x=0;int f=0;char ch=getchar();
      while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
      while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
      x= f ? -x : x ;
    }
    
    int max(int x,int y){return x>y ? x : y ;}
    
    void update(Splay &ret,Splay lx,Splay ry){
      ret.size=lx.size+ry.size+1;
      ret.sum=lx.sum+ry.sum+ret.val;
      ret.lmax=max(lx.lmax,lx.sum+ret.val+ry.lmax);
      ret.rmax=max(ry.rmax,ry.sum+ret.val+lx.rmax);
      ret.dat=max(max(lx.dat,ry.dat),lx.rmax+ret.val+ry.lmax);//给0赋值防止了出事
      //printf("-%d-",ret.val);
    }
    
    void update(int x){
      update(tr[x],tr[tr[x].s[0]],tr[tr[x].s[1]]);
    }
    
    int build(int l,int r,int f){
      //printf("%d %d
    ",l,r);
      if(l>r) return 0;
      int mid=(l+r)>>1,now=id[mid];
      tr[now].fa=f;
      tr[now].val=a[mid];
      tr[now].cover=oo;
      if(l==r){
        tr[now].size=1;
        tr[now].sum=tr[now].val;
        tr[now].lmax=tr[now].rmax=max(0,tr[now].val);
        tr[now].dat=tr[now].val;//记得赋值
        return now;
      }
      tr[now].s[0]=build(l,mid-1,now);
      tr[now].s[1]=build(mid+1,r,now);
      update(now);
      return now;
    }
    
    void put_cover(int x,int val){
      if(!x) return ;
      tr[x].val=tr[x].cover=val;
      tr[x].sum=val*tr[x].size;
      tr[x].lmax=tr[x].rmax= val>=0 ? tr[x].sum : 0;
      tr[x].dat= val>=0 ? tr[x].sum : val;//必须选取至少一个元素
    }
    
    void put_tag(int x){
      if(!x) return ;
      tr[x].tag^=1;
      swap(tr[x].s[0],tr[x].s[1]);
      swap(tr[x].lmax,tr[x].rmax);
    }
    
    void push_down(int x){
      if(tr[x].cover!=oo){
        put_cover(tr[x].s[0],tr[x].cover);
        put_cover(tr[x].s[1],tr[x].cover);
        tr[x].cover=oo;
      }
      if(tr[x].tag){
        put_tag(tr[x].s[0]);
        put_tag(tr[x].s[1]);
        tr[x].tag=0;
      }
    }
    
    void debug(int x){
      push_down(x);
      if(tr[x].s[0]) debug(tr[x].s[0]);
      printf("%d ",tr[x].val);
      if(tr[x].s[1]) debug(tr[x].s[1]);
    }
    
    int find(int k){
      int now=root;
      while(1){
        //printf("%d %d
    ",k,now);
        push_down(now);
        if(tr[tr[now].s[0]].size>=k) {now=tr[now].s[0];continue;}
        k-=tr[tr[now].s[0]].size;
        if(k==1) return now;
        k--;
        now=tr[now].s[1];
      }
    }
    
    int get(int x){
      return tr[tr[x].fa].s[1]==x;
    }
    
    void connect(int x,int y,int d){
      tr[y].s[d]=x;
      tr[x].fa=y;
    }
    
    void rotate(int x){
      int f=tr[x].fa,ff=tr[f].fa;
      int d1=get(x),d2=get(f);
      int cs=tr[x].s[d1^1];
      connect(x,ff,d2);
      connect(f,x,d1^1);
      connect(cs,f,d1);
      update(f);
      update(x);
    }
    
    void splay(int x,int go){
      if(go==root) root=x;
      go=tr[go].fa;
      while(tr[x].fa!=go){
        int f=tr[x].fa;
        if(tr[f].fa==go) rotate(x);
        else if(get(x)==get(f)) {rotate(f);rotate(x);}
        else {rotate(x);rotate(x);}
      }
    }
    
    void insert(){
      int pos,tot;
      read(pos);read(tot);n+=tot;
      for(int i=1;i<=tot;i++){
        read(a[i]);
        if(!q.empty()) id[i]=q.front(),q.pop();
        else id[i]=++num;
      }
      int nowroot=build(1,tot,0);
      int x=find(pos+1),y=find(pos+2);
      splay(x,root);
      splay(y,tr[x].s[1]);
      tr[nowroot].fa=y;
      tr[y].s[0]=nowroot;
      update(y);
      update(x);
    }
    
    void clean(int x){
      tr[x]=(Splay){{0,0},0,0,0,oo,0,0,0,0,0};
    }
    
    void recycle(int x){
      if(tr[x].s[0]) recycle(tr[x].s[0]);
      if(tr[x].s[1]) recycle(tr[x].s[1]);
      clean(x);
      q.push(x);
    }
    
    void dele(){
      int pos,tot;
      read(pos);read(tot);n-=tot;
      int x=find(pos),y=find(pos+tot+1);
      splay(x,root);
      splay(y,tr[x].s[1]);
      recycle(tr[y].s[0]);
      tr[y].s[0]=0;
      update(y);
      update(x);
    }
    
    void modify(){
      int pos,tot;
      int val;
      read(pos);read(tot);read(val);
      int x=find(pos),y=find(pos+tot+1);
      splay(x,root);
      splay(y,tr[x].s[1]);
      put_cover(tr[y].s[0],val);
      update(y);
      update(x);
    }
    
    void reverse(){
      int pos,tot;
      read(pos);read(tot);
      int x=find(pos),y=find(pos+tot+1);
      splay(x,root);
      splay(y,tr[x].s[1]);
      put_tag(tr[y].s[0]);
      update(y);
      update(x);
    }
    
    int querysum(){
      int pos,tot;
      read(pos);read(tot);
      int x=find(pos),y=find(pos+tot+1);
      splay(x,root);
      splay(y,tr[x].s[1]);
      //printf("%d %d
    ",x,y);
      //printf("%d
    ",tr[tr[y].s[0]].size);
      //putchar(10);
      //debug(tr[y].s[0]);
      //putchar(10);
      return tr[tr[y].s[0]].sum;
    }
    
    int querydat(){
      int x=find(1),y=find(n);
      splay(x,root);
      splay(y,tr[x].s[1]);
      return tr[tr[y].s[0]].dat;
    }
    
    int main(){
      read(n);read(m);
      tr[0].dat=a[1]=a[n+2]=-oo;//给零赋值,不然建树会出锅
      for(int i=1;i<=n;i++) read(a[i+1]);
      for(int i=1;i<=n+2;i++) id[i]=++num;
      n=n+2;
      root=build(1,n,0);
      for(int i=1;i<=m;i++){
        char opt[15];
        scanf("%s",opt);
        if(opt[2]=='S') insert();
        else if(opt[2]=='L') dele();
        else if(opt[2]=='K') modify();
        else if(opt[2]=='V') reverse();
        else if(opt[2]=='T') printf("%d
    ",querysum());
        else printf("%d
    ",tr[root].dat);
        //putchar(10);
        //debug(root);
        //putchar(10);
      }
    }
    维护数列
  • 相关阅读:
    短期阅读的书籍
    Expert .NET 2.0 IL Assembler 译者序
    Prism研究(for WPF & Silverlight)4.从Hello World开始(实战篇)
    (翻译) 《C# to IL》第一章 IL入门
    不申请连任MVP了,把机会留给新人吧!
    (翻译) 《C# to IL》第三章 选择和循环
    Prism研究(for WPF & Silverlight) 13
    (翻译) 《C# to IL》第二章 IL基础
    Resharper使用体会及一些资料
    推荐一个PD Report Model
  • 原文地址:https://www.cnblogs.com/sto324/p/11297521.html
Copyright © 2011-2022 走看看