Splay专题

来源:互联网 发布:php视频解析源码 编辑:程序博客网 时间:2024/06/05 11:10

建树

void build(int l,int r,int &id,int f){     if(l>r)return;    int mid=(l+r)>>1;    New(id,f,A[mid]);     build(l,mid-1,ch[id][0],id);    build(mid+1,r,ch[id][1],id);     up(id);  }void init(int n){     ch[0][0]=ch[0][1]=sz[0]=par[0]=val[0]=0;//初始化空地址    sum[0]=dly[0]=0;    root=0;num=0;    New(root,0,0);//先把0插入到树中    New(ch[root][1],root,0);//在把n+1插入到树中     for(int i=1;i<=n;i++)scanf("%d",&A[i]);    build(1,n,ch[ch[root][1]][0],ch[root][1]);//建成一棵比较平衡的二叉树放进去     up(ch[root][1]);    up(root); } 

基本模板

void New(int &id,int f,int v){    id=++num;    val[id]=v;     ch[id][0]=ch[id][1]=0;    par[id]=f;    sum[id]=dly[id]=0;    sz[id]=1;}void rotate(int x){    //rotate部分不需要down了,找到x时,rotateTo函数已经把x所有的父亲都down了     int y=par[x];      int d=ch[y][0]==x;//d=1右旋,d=0左旋     //3根线发生变化    ch[y][!d]=ch[x][d];    if(ch[x][d])par[ch[x][d]]=y;//第一根线    par[x]=par[y];//第二根     if(par[y])ch[par[y]][ch[par[y]][1]==y]=x;     ch[x][d]=y;par[y]=x;//第三根     up(y);    //x不需要up,因为x还要继续往上旋 } void Splay(int x,int goal){     //当x的父亲和爷爷不在一个方向时,旋两次x    //否则,先旋父亲,再旋x     while(par[x]!=goal){         int y=par[x];        if(par[y]==goal)rotate(x);        else{            int z=par[y];            if(ch[z][0]==y^ch[y][0]==x)rotate(x);            else rotate(y);            rotate(x);         }     }      up(x);    if(goal==0)root=x; }void rotateTo(int k,int goal){    //因为0也占了一个位置,所以第k个数,就变成左边有x个数的位置。     int p=root;    down(p);//因为可能有翻转操作,左右儿子先需要交换,每次都先down一下    while(sz[ch[p][0]]!=k){          if(sz[ch[p][0]]>k){//在左儿子中             p=ch[p][0];        }else{//在右儿子中              k-=sz[ch[p][0]]+1;             p=ch[p][1];        }        down(p);     }      Splay(p,goal);//p就是第k个数所在的内存地址 }

功能

<1>查找前驱后继

int lower(int x){int cur=root,mi=1e9;    while(cur){         if(val[cur]==x)return 0;        if(val[cur]<x){            mi=min(mi,x-val[cur]);            cur=ch[cur][1];        }else cur=ch[cur][0];    }return mi;}int upper(int x){    int cur=root,mi=1e9;    while(cur){         if(val[cur]==x)return 0;        if(val[cur]>x){            mi=min(mi,val[cur]-x);            cur=ch[cur][0];        }else cur=ch[cur][1];    }return mi;}

<2>

void delt(){    //更新因为删除该节点所改变的信息    int pre=get_pre();    int nxt=get_nxt();    int rot=root;    if(pre==-1)root=ch[root][1];    else if(nxt==-1)root=ch[root][0];    if(~pre&&~nxt){        Splay(pre,root);        par[pre]=nxt;//把前驱接在后继上        ch[nxt][0]=pre;        root=ch[root][1];//以原来的右儿子为根    }par[root]=0;}

<3>lowupper

类似于二分;如果找low。
我们对于val < x 的节点更新答案然后到它的右节点上(使val变大)
反之则到左节点上

int lower(int x){    int cur=root,ans=-1e9;    while(cur){         if(val[cur]<=x){            ans=max(ans,val[cur]);            cur=ch[cur][1];        }else cur=ch[cur][0];    }return ans;}int upper(int x){    int cur=root,ans=1e9;    while(cur){         if(val[cur]>=x){            ans=min(ans,val[cur]);            cur=ch[cur][0];        }else cur=ch[cur][1];    }return ans;}

<4>区间查询和更新

如图我们只需把l-1旋到根在把r+1旋上去那么r+1的左子树即为我们要的区间
这里写图片描述

void update(int l,int r,int v){    rotateTo(l-1,0);//以l-1为root    rotateTo(r+1,root);//以r+1为ch[root][1]    int need=ch[ch[root][1]][0];//need就为[l,r]     dly[need]+=v;//delay延迟更新     val[need]+=v;    sum[need]+=1ll*v*sz[need];}ll query(int l,int r){    rotateTo(l-1,0);     rotateTo(r+1,root);    return sum[ch[ch[root][1]][0]];} 

<5> 翻转和覆盖
利用down来延迟更新

    void down_c(int p,int c){        cov[p]=1;val[p]=c;        sum[p]=sz[p]*c;        mx[p]=lsum[p]=rsum[p]=max(c,sum[p]);    }    void down_r(int p){        rev[p]^=1;        swap(ch[p][0],ch[p][1]);        swap(lsum[p],rsum[p]);    }    void down(int p){        int l=ch[p][0],r=ch[p][1];        if(rev[p]){             if(l)down_r(l);            if(r)down_r(r);             rev[p]=0;        }        if(cov[p]){              if(l)down_c(l,val[p]);            if(r)down_c(r,val[p]);            cov[p]=0;        }    }

注意在Splay和RotateTo的过程中都有可能要down

<6>区间插入
直接套用build来建一个新子树

    void insert(){         int pos,m;        scanf("%d %d",&pos,&m);        for(int i=1;i<=m;i++)scanf("%d",&A[i]);         rotateTo(pos,0);        rotateTo(pos+1,root);        build(1,m,key,ch[root][1]);//直接使用build来构建         up(ch[root][1]);up(root);    }

<7>区间删除
为了使内存更优,我们用一个stk收集被删除的节点

    void Dfs_del(int k){        stk[++top]=k;        if(ch[k][0])Dfs_del(ch[k][0]);        if(ch[k][1])Dfs_del(ch[k][1]);    }    void delt(){        int pos,m;        scanf("%d %d",&pos,&m);        selc(pos,pos+m-1);          Dfs_del(key);        key=0;        up(ch[root][1]);up(root);      } 

全家福

#include<bits/stdc++.h>using namespace std;const int M=600005,INF=1e9;int A[M],n,m;struct SplayT{    #define key ch[ch[root][1]][0]    int val[M],sz[M],par[M],ch[M][2];    bool rev[M],cov[M];    int stk[M],top;    int mx[M],lsum[M],rsum[M],sum[M];    int num,root;    void New(int &id,int f,int v){        if(top)id=stk[top--];        else id=++num;        val[id]=v;ch[id][0]=ch[id][1]=0;par[id]=f;        sum[id]=0;sz[id]=1;        cov[id]=rev[id]=0;        mx[id]=lsum[id]=rsum[id]=v;    }    void down_c(int p,int c){        cov[p]=1;val[p]=c;        sum[p]=sz[p]*c;        mx[p]=lsum[p]=rsum[p]=max(c,sum[p]);    }    void down_r(int p){        rev[p]^=1;        swap(ch[p][0],ch[p][1]);        swap(lsum[p],rsum[p]);    }    void up(int p){        sum[p]=val[p];        sz[p]=1;        int l=ch[p][0],r=ch[p][1];        sum[p]+=sum[l]+sum[r];        sz[p]+=sz[l]+sz[r];         mx[p]=max(max(mx[l],mx[r]),max(0,rsum[l])+val[p]+max(lsum[r],0));        lsum[p]=max(lsum[l],sum[l]+val[p]+max(lsum[r],0));        rsum[p]=max(rsum[r],sum[r]+val[p]+max(rsum[l],0));    }     void down(int p){        int l=ch[p][0],r=ch[p][1];        if(rev[p]){             if(l)down_r(l);            if(r)down_r(r);             rev[p]=0;        }        if(cov[p]){              if(l)down_c(l,val[p]);            if(r)down_c(r,val[p]);            cov[p]=0;        }    }    void build(int l,int r,int &id,int f){         if(l>r)return;        int mid=(l+r)>>1;        New(id,f,A[mid]);         build(l,mid-1,ch[id][0],id);        build(mid+1,r,ch[id][1],id);         up(id);      }    void init(int n){        ch[0][0]=ch[0][1]=sz[0]=par[0]=0; //初始化空地址        sum[0]=0;val[0]=0;mx[0]=lsum[0]=rsum[0]=-INF;        rev[0]=cov[0]=0;        root=0;num=0;top=0;        New(root,0,-INF);//0        New(ch[root][1],root,-INF);//n+1        for(int i=1;i<=n;i++)scanf("%d",&A[i]);        build(1,n,ch[ch[root][1]][0],ch[root][1]);        up(ch[root][1]);        up(root);    }    void Splay(int x,int goal=0){        while(par[x]!=goal){            int y=par[x];            if(par[y]!=goal){                if(ch[par[y]][0]==y^ch[y][0]==x)rotate(x);                else rotate(y);            }rotate(x);        }up(x);        if(!goal)root=x;    }    void rotateTo(int k,int goal){          int cur=root;        down(cur);        while(sz[ch[cur][0]]!=k){            if(sz[ch[cur][0]]>k)cur=ch[cur][0];            else k-=1+sz[ch[cur][0]],cur=ch[cur][1];            down(cur);        }Splay(cur,goal);    }    void rotate(int x){        int y=par[x];        int d=ch[y][0]==x;        ch[y][!d]=ch[x][d];        if(ch[x][d])par[ch[x][d]]=y;        par[x]=par[y];        if(par[y])ch[par[y]][ch[par[y]][1]==y]=x;        ch[x][d]=y;        par[y]=x;        up(y);    }    void selc(int l,int r){        rotateTo(l-1,0);        rotateTo(r+1,root);    }    void reverse(){        int l,c;        scanf("%d %d",&l,&c);        selc(l,c+l-1);        down_r(key);        up(ch[root][1]);up(root);//操作完了搜集信息     }       void mark_same(){        int l,c,x;        scanf("%d %d %d",&l,&c,&x);        selc(l,c+l-1);        down_c(key,x);        up(ch[root][1]);up(root);    }    void get_Sum(){        int l,c;        scanf("%d %d",&l,&c);        selc(l,c+l-1);        printf("%d\n",sum[key]);    }    void Dfs_del(int k){        stk[++top]=k;        if(ch[k][0])Dfs_del(ch[k][0]);        if(ch[k][1])Dfs_del(ch[k][1]);    }    void delt(){        int pos,m;        scanf("%d %d",&pos,&m);        selc(pos,pos+m-1);          Dfs_del(key);        key=0;        up(ch[root][1]);up(root);      }     void insert(){         int pos,m;        scanf("%d %d",&pos,&m);        for(int i=1;i<=m;i++)scanf("%d",&A[i]);         rotateTo(pos,0);        rotateTo(pos+1,root);        build(1,m,key,ch[root][1]);//直接使用build来构建         up(ch[root][1]);up(root);    }    void get_max(){        printf("%d\n",mx[root]);    }}T;void solve(){    scanf("%d %d",&n,&m);    char s[215];    T.init(n);    for(int i=1;i<=m;i++){        scanf("%s",s);        if(s[0]=='I')T.insert();        if(s[0]=='M'){            if(s[2]=='X')T.get_max();            else T.mark_same();        }if(s[0]=='D')T.delt();        if(s[0]=='R')T.reverse();        if(s[0]=='G')T.get_Sum();    }}int main(){    solve();    return 0;}
1 0
原创粉丝点击