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);
      }
    }
    维护数列
  • 相关阅读:
    基本MVVM 和 ICommand用法举例(转)
    WPF C# 命令的运行机制
    628. Maximum Product of Three Numbers
    605. Can Place Flowers
    581. Shortest Unsorted Continuous Subarray
    152. Maximum Product Subarray
    216. Combination Sum III
    448. Find All Numbers Disappeared in an Array
    268. Missing Number
    414. Third Maximum Number
  • 原文地址:https://www.cnblogs.com/sto324/p/11297521.html
Copyright © 2011-2022 走看看