【bzoj 1251】序列终结者

题目在这里

这应该是splay裸题了吧。对于每个节点保存5个值,size,_max,flag,lazy,val 分别表示这个节点的子树大小,子树的最大值,子树是否有打过翻转标记,子树的增加的值,(前面的所有都包括这个节点它自己),以及这个节点的当前值。对于一段区间[L,R]的询问/修改,只需把L-1这个节点旋转到根,再把R+1这个节点旋转到根的右儿子。这样R+1节点的左子树就对应[L,R]这个区间,之后就直接在它的左儿子上打标记/询问就行了。当然为了方便新建两个节点一个代表0,另一个代表n+1。(好像学名叫僵尸节点。。。)对于Add操作,直接所有值加v;而对于翻转操作,直接交换这个节点的左右儿子就行了(大概意会一下)。注意这样搞完之后,下标为i的节点不一定代表s[i],而是要根据二叉查找树的定义查找(比如当前找第k个点,如果左子树大小小于k-1就往左子树里找,如果等于k-1就是它自己,如果大于k-1就k-=size[lson[x]],然后往右子树里找)。pushdown操作类比一下线段树,即只要到这个点就把它的pushdown下去,然后把这个点的标记清空。然后每次干完之后update一下(注意最大值还要跟当前的val比较)。这样应该就差不多了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <deque>
#include <queue>
#include <map>
#include <set>
#include <ctime>
using namespace std;

const int MAXN=50005,INF=(1<<29);
int n,m,root; 

class Splay_Tree
{   
    int fa[MAXN],ch[MAXN][2],size[MAXN],_max[MAXN],val[MAXN],lazy[MAXN]; bool turn[MAXN]; 

    void modify(int x) { if (x==0) return; turn[x]^=1; }
    void Add(int x,int v) { if (x==0) return; _max[x]+=v,val[x]+=v,lazy[x]+=v; }
    void update(int x) 
      { 
        int l=ch[x][0],r=ch[x][1]; size[x]=1,_max[x]=val[x]; 
        if (l) size[x]+=size[l],_max[x]=max(_max[x],_max[l]); 
        if (r) size[x]+=size[r],_max[x]=max(_max[x],_max[r]);
      }

    void pushdown(int x) 
      {     
        if (lazy[x]) Add(ch[x][0],lazy[x]),Add(ch[x][1],lazy[x]),lazy[x]=0; 
        if (turn[x]) swap(ch[x][0],ch[x][1]),modify(ch[x][0]),modify(ch[x][1]),turn[x]=false; 
      } 

    void Rotate(int x,int d)
      { 
        int y=fa[x],z=fa[y]; ch[y][d^1]=ch[x][d],fa[ch[x][d]]=y; 
        if (z) ch[z][ch[z][1]==y]=x; fa[x]=z,ch[x][d]=y,fa[y]=x;  
        update(y); 
      } 

    void splay(int x,int goal)
      { 
        pushdown(x);
        while (fa[x]!=goal)
          { 
            int y=fa[x],z=fa[y]; 
            if (z==goal) Rotate(x,ch[y][0]==x); 
            else  
              {
                int f=(ch[z][0]==y);
                if (ch[y][f^1]==x) Rotate(y,f),Rotate(x,f); else Rotate(x,f^1),Rotate(x,f);
              }
          }
        update(x); 
        if (goal==0) root=x; 
      }

    int Find(int x)
      { 
        int nowx=root; pushdown(nowx);
        while (size[ch[nowx][0]]+1!=x) 
          { 
            if (size[ch[nowx][0]]+1<x) x-=size[ch[nowx][0]]+1,nowx=ch[nowx][1];else nowx=ch[nowx][0];
            pushdown(nowx);  
          } 
        return nowx; 
      }

    public:

    void Build_Tree(int l,int r,int f)
      { 
        if (l>r) return; 
        int mid=(l+r)>>1; 
        if (f) fa[mid]=f,ch[f][mid>f]=mid;else root=mid,fa[mid]=0;
        val[mid]=0,_max[mid]=0,lazy[mid]=0,size[mid]=1;
        Build_Tree(l,mid-1,mid),Build_Tree(mid+1,r,mid); update(mid);
      }

    void modify(int Ql,int Qr)
      {
        int keyx=select(Ql+1,Qr+1); 
        modify(keyx); splay(keyx,0); 
      }

    void Add(int Ql,int Qr,int v)
      { 
        int keyx=select(Ql+1,Qr+1);
        Add(keyx,v); splay(keyx,0);  
      } 

    void Query(int Ql,int Qr)
      { 
        int keyx=select(Ql+1,Qr+1); 
        printf("%d\n",_max[keyx]);
        splay(keyx,0);
      }

    int select(int Ql,int Qr)
      { 
        int L=Find(Ql-1),R=Find(Qr+1);
        splay(L,0),splay(R,L); 
        return ch[R][0]; 
     }

    /*void debug(int x)   
      { 
        printf("No.%d size=%d max=%d val=%d lazy=%d ls=%d rs=%d\n ",x,size[x],_max[x],val[x],lazy[x],
        ch[x][0],ch[x][1]);
        if (ch[x][0]) debug(ch[x][0]);
        if (ch[x][1]) debug(ch[x][1]);
      }*/
}T;

int Get()
{
    char ch; int v=0; bool f=false;
    while (!isdigit(ch=getchar())) if (ch=='-') f=true; v=ch-48;
    while (isdigit(ch=getchar())) v=v*10+ch-48;
    if (f) return -v;else return v;     
}

int main()
{ 
    //freopen("terminator.in","r",stdin);
    //freopen("terminator.out","w",stdout);
    n=Get(),m=Get(); int type,l,r,v; 
    T.Build_Tree(1,n+2,0); 
    while (m--)
      { 
        type=Get(),l=Get(),r=Get(); 
        if (type==1) v=Get(),T.Add(l,r,v); 
        if (type==2) T.modify(l,r);
        if (type==3) T.Query(l,r);
      }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值