当初学 Splay树 所看过的,凭理解打过的代码

来源:互联网 发布:仓廪实则知礼节的例子 编辑:程序博客网 时间:2024/05/16 15:49

 

 

HDU 1890

 

这是我第一次接触Splay树时,所接触的代码。

那位大牛的博客我现在找不到了#。#。抱歉ing..

 

思路就是区间翻转,主要是将n个数通过树的先序访问保存下来。

这样旋转的时候就不会出现问题

 

代码:

 

////  1890.cpp//  ACM_HDU////  Created by ipqhjjybj on 13-8-27.//  Copyright (c) 2013年 ipqhjjybj. All rights reserved.//  参考着别人Ac代码敲的//#include <cstdio>#include <algorithm>#include <map>using namespace std;struct SplayTree{    const static int maxn=111111;    int n,tot,root;    map<int,int> Map;    int child[maxn][2];    int pre[maxn],size[maxn],flex[maxn];    int id[maxn];    struct node{        int id,val;        bool operator < (const node & tmp) const{            return val<tmp.val||(val==tmp.val&&id<tmp.id);        }    }in[maxn];    void Pushup(int &x){        size[x]=size[child[x][0]]+size[child[x][1]]+1;    }    void Pushdown(int &x){        if(flex[x]){            flex[x]=0;            flex[child[x][0]]^=1;            flex[child[x][1]]^=1;            swap(child[x][0],child[x][1]);        }    }    void Del_root(){        int t=root;        if(child[root][1]){            root=child[root][1];            Select(1,0);            child[root][0]=child[t][0];            if(child[t][0]) pre[child[t][0]]=root;        }else            root=child[root][0];        pre[root]=0;        Pushup(root);    }    // c==0  左旋 ,  c==1 右旋    inline void Rotate(int x, int c) {    // 旋转, c=0 左旋, c=1 右旋        int y = pre[x];        Pushdown(y);        Pushdown(x);        child[y][!c] = child[x][c];        if ( child[x][c] )    pre[ child[x][c] ] = y;        pre[x] = pre[y];        if ( pre[y] )    child[ pre[y] ][ child[pre[y]][1] == y ] = x;        child[x][c] = y;        pre[y] = x;        Pushup(y);    }    void Splay(int x,int f){       // puts("fuck Splay");        Pushdown(x);        while(pre[x]!=f){        //    printf("f=%d pre[%d]=%d\n",f,x,pre[x]);            int y=pre[x],z=pre[y];            Pushdown(z),Pushdown(y),Pushdown(x);            if(pre[pre[x]]==f){                Rotate(x,child[pre[x]][0]==x);            }else{                if ( child[z][0] == y ) {                    if ( child[y][0] == x )                        Rotate(y, 1), Rotate(x, 1);                    else                        Rotate(x, 0), Rotate(x, 1);                }                else {                    if ( child[y][0] == x )                        Rotate(x, 1), Rotate(x, 0);                    else                        Rotate(y, 0), Rotate(x, 0);                }            }        }        Pushup(x);        if(f==0) root=x;    }    void Select(int k,int f){        int x=root;        while(1){            Pushdown(x);            if(k==size[child[x][0]]+1)                break;            if(k<=size[child[x][0]])                x=child[x][0];            else{                k-=size[child[x][0]]+1;                x=child[x][1];            }        }        Splay(x,f);    }    void Newnode(int &x,int f){        //puts("fuck newnode");        x=++tot;        child[x][0]=child[x][1]=0;        pre[x]=f;        flex[x]=0;        size[x]=1;    }    void Build(int &x,int l,int r,int f){        if(l>r)return;        int mid=(l+r)>>1;        //puts("Fuck(Build)");        Newnode(x,f);        Map[id[mid]]=x;        Build(child[x][0],l,mid-1,x);        Build(child[x][1],mid+1,r,x);        Pushup(x);    }    void init(int _n){        n=_n; Map.clear(); root=tot=0;        pre[0]=child[0][0]=child[0][1]=0;        size[0]=flex[0]=0;        for(int i=1;i<=n;i++){            scanf("%d",&in[i].val);            in[i].id=i;        }        sort(in+1,in+1+n);        for(int i=1;i<=n;i++)            id[in[i].id]=i;        Map[id[1]]=1;        Map[id[n]]=2;        Newnode(root,0);        Newnode(child[root][1],root);        Build(child[child[root][1]][0],2,n-1,child[root][1]);        Pushup(child[root][1]);        Pushup(root);    }    void solve(int n){        for(int i=1;i<=n;i++){            //printf("i=%d\n",i);            //printf("Map[%d]=%d\n",i,Map[i]);            Splay(Map[i],0);            //printf("root=%d\n",root);            printf("%d%c",i+size[child[root][0]],i==n?'\n':' ');            flex[child[root][0]]^=1;            Del_root();        }    }}spt;int main(){    int n;    while(scanf("%d",&n)&&n){        if(n==1){scanf("%*d");puts("1");continue;}        spt.init(n);        spt.solve(n);    }    return 0;}

 

 

 

HDU 3487

 


别人都说这是水题。。

设计到Splay的基本操作,区间翻转及区间插入。。

对[l,r]这段区间,要想获得的话,先将l-1这个节点翻转到根节点,再把r+1这个节点翻转到根节点之下。

这样KeyTree  child[child[root][1]][0] 所表示的那段就是区间[l,r]了。 之后再进行区间的删除跟插入。

找到要插入的区间,比如插到i之后,就先把i旋转到根节点,然后然后把i的右子树中的最小的那个点旋转到根下面,这样这个最小点的左节点就是空的节点,可以插入那段区间了。

翻转的操作反而更加简单, 只用获得节点,传递一个修改的标记的就好了。

 

http://blog.csdn.net/acm_cxlove/article/details/7795244 原博客

代码:

////  3487.cpp//  ACM_HDU////  Created by ipqhjjybj on 13-9-6.//  Copyright (c) 2013年 ipqhjjybj. All rights reserved.//  先看完别人代码。后来凭记忆敲的Ac代码//#include<iostream>#include<cstring>#include<queue>#include<cstdio>#include<algorithm>#define N 300015#define inf 1<<29#define MOD 100000007#define LL long long#define _match(a,b) ((a)==(b))#define Key_value ch[ch[root][1]][0]using namespace std;int n,q;int size[N],pre[N],key[N],num[N],rev[N];int ch[N][2],tot,root,node[N];void Push_Up(int &t){    size[t]=size[ch[t][0]]+size[ch[t][1]]+1;}void Push_Down(int &t){    if(rev[t]){        swap(ch[t][0],ch[t][1]);        rev[ch[t][0]]^=1;        rev[ch[t][1]]^=1;        rev[t]=0;    }}void NewNode(int &t,int k,int father){    t=++tot;    pre[t]=father;    key[t]=k;    rev[t]=0;    ch[t][0]=ch[t][1]=0;}void Build(int &t,int l,int r,int father){    if(l>r)return;    int mid=(l+r)>>1;    NewNode(t,mid,father);    Build(ch[t][0],l,mid-1,t);    Build(ch[t][1],mid+1,r,t);    Push_Up(t);}void Init(){    root=tot=0;    ch[root][0]=ch[root][1]=pre[root]=rev[root]=size[root]=0;    NewNode(root,-1,0);    NewNode(ch[root][1],-1,root);    size[root]=2;    Build(Key_value,1,n,ch[root][1]);    Push_Up(ch[root][1]);    Push_Up(root);}void Rotate(int x,int c){ // c==0左旋,c==1右旋    int y=pre[x];    Push_Down(y);    Push_Down(x);    ch[y][!c]=ch[x][c];    pre[ch[x][c]]=y;    if(pre[y])        ch[pre[y]][ch[pre[y]][1]==y]=x;    pre[x]=pre[y];    ch[x][c]=y;    pre[y]=x;    Push_Up(y);}void Splay(int x,int father){    Push_Down(x);    while(pre[x]!=father){        int y=pre[x],z=pre[y];        Push_Down(z),Push_Down(y),Push_Down(z);        if(pre[y]==father){            Rotate(x,ch[y][0]==x);        }else{            if(ch[z][0]==y){                if(ch[y][0]==x)                    Rotate(y,1),Rotate(x,1);                else Rotate(x,0),Rotate(x,1);            }else{                if(ch[y][0]==x)                    Rotate(x,1),Rotate(x,0);                else Rotate(y,0),Rotate(x,0);            }        }    }    Push_Up(x);    if(father==0) root=x;}int Get_Kth(int t,int k){    Push_Down(t);    if(size[ch[t][0]]==k-1)        return t;    else if(size[ch[t][0]]>=k)        return Get_Kth(ch[t][0],k);    else return Get_Kth(ch[t][1],k-size[ch[t][0]]-1);}int Min_Value(int t){    Push_Down(t);    while(ch[t][0]){        t=ch[t][0];        Push_Down(t);    }    return t;}void Reversal(int a,int b){    a=Get_Kth(root,a);    b=Get_Kth(root,b+2);    Splay(a,0);    Splay(b,root);    rev[Key_value]^=1;}void Cut(int a,int b,int c){    int x=Get_Kth(root,a);    int y=Get_Kth(root,b+2);    Splay(x,0);    Splay(y,root);    int tmp=Key_value;    Key_value=0;    Push_Up(ch[root][1]);    Push_Up(root);    int cm=Get_Kth(root,c+1);    Splay(cm,0);    int mi=Min_Value(ch[root][1]);    Splay(mi,root);    Key_value=tmp;    pre[Key_value]=ch[root][1];    Push_Up(ch[root][1]);    Push_Up(root);}int cnt;void InOrder(int r){    if(r==0)        return;    Push_Down(r);    InOrder(ch[r][0]);    if(cnt>=1&&cnt<=n){        if(cnt>1)printf(" ");        printf("%d",key[r]);    }    cnt++;    InOrder(ch[r][1]);}int main(){    while(scanf("%d%d",&n,&q)!=EOF){if(n==-1&&q==-1)break;Init();while(q--){char str[10];int a,b,c;scanf("%s",str);if(str[0]=='C'){scanf("%d%d%d",&a,&b,&c);Cut(a,b,c);}else{scanf("%d%d",&a,&b);Reversal(a,b);}}cnt=0;InOrder(root);printf("\n");}return 0;}

 

 

HDU 3436

 

这道题是离散化数据来进行Splay。  非常感谢这位大牛的代码。

很有借鉴的意义。。  区间的离散, 把需要的点单独存,end跟beg都为1,不然就保存的时候, 1到a1-1就保存成 beg=1, end=a1-1这样类似的。。

理解后就感觉不难了。   

原博客:http://blog.sina.com.cn/s/blog_6c7729450100uvye.html

代码:

////  3436.cpp//  ACM_HDU////  Created by ipqhjjybj on 13-9-7.//  Copyright (c) 2013年 ipqhjjybj. All rights reserved.//  先看完别人代码的。。//#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>using namespace std;const int MAXN = 222222;int n,q,k,N;char re[MAXN];int req[MAXN],a[MAXN],na,beg[MAXN],end[MAXN];int num[MAXN],pre[MAXN],ch[MAXN][2],root;void flow(int x){    num[x]=num[ch[x][0]]+num[ch[x][1]]+end[x]-beg[x]+1;}inline void rotate(int n){    int t=pre[n];    bool isr=(ch[t][1]==n);    ch[t][isr]=ch[n][!isr],pre[ch[n][!isr]]=t;    pre[n]=pre[t],ch[pre[t]][ch[pre[t]][1]==t]=n;    pre[t]=n,ch[n][!isr]=t;    flow(t);}inline void splay(int n,int goal){    int f,ff;    while(pre[n]!=goal)    {        f=pre[n],ff=pre[f];        if(goal==ff)            rotate(n);        else if((ch[ff][1]==f)==(ch[f][1]==n))            rotate(f),rotate(n);        else            rotate(n),rotate(n);    }    flow(n);    if(!goal)        root=n;}void Top(int t){    splay(t,0);    int x=ch[t][1];    while(ch[x][0])        x=ch[x][0];    splay(x,t);    ch[x][0]=ch[t][0],pre[ch[t][0]]=x;    ch[t][0]=0;    //因为算法的特殊性.root不能变为t;    flow(t);}int Rank(int n){    int t=root;    while(1){        if(num[ch[t][0]]<n&&num[ch[t][0]]+end[t]-beg[t]+1>=n)            break;        if(n<=num[ch[t][0]])            t=ch[t][0];        else {            n-=num[ch[t][0]]+end[t]-beg[t]+1,t=ch[t][1];        }    }    int ans=beg[t]+n-1-num[ch[t][0]];    splay(t,0);    return ans;}int Query(int x){    splay(x,0);    return num[ch[x][0]]+1;}int Bisearch(int n){    int l=1,r=N,mid;    while(l<=r)    {        mid=(l+r)>>1;        if(beg[mid]>n)            r=mid-1;        else if(end[mid]<n)            l=mid+1;        else            return mid;    }    return l;}int main(){    int t,tt=0,val,i,j;    char str[10];    scanf("%d",&t);    while(t--){        scanf("%d %d",&n,&q);        k=0;        na=0;        for(i=0;i<q;i++){            scanf("%s %d",str,&val);            re[k]=str[0],req[k++]=val;            if(str[0]=='T'){                a[na++]=val;            }        }        sort(a,a+na);        for(j=i=1;i<na;i++)            if(a[i]!=a[i-1])                a[j++]=a[i];        na=j;j=1;        if(a[0]>1){            beg[j]=1,end[j++]=a[0]-1;        }        for(i=0;i<na;i++){            end[j]=beg[j]=a[i],j++;            if(i<na-1){                if(a[i]+1<a[i+1]){                    beg[j]=a[i]+1,end[j]=a[i+1]-1;                    j++;                }            }else{               beg[j]=a[i]+1,end[j]=n,j++;            }        }        beg[j]=end[j]=n+1;j++;        memset(ch,0,sizeof(int)*(j+2)*2);        num[0]=0,N=j-1;        for(i=1;i<=N;i++){            num[i]=num[i-1]+end[i]-beg[i]+1;            pre[i-1]=i,ch[i][0]=i-1;        }pre[N]=0;        root=N;        printf("Case %d:\n",++tt);        for(i=0;i<k;i++){            if(re[i]=='T'){                Top(Bisearch(req[i]));            }else if(re[i]=='R'){                printf("%d\n",Rank(req[i]));            }else{                j=Bisearch(req[i]);                printf("%d\n",Query(j)+req[i]-beg[j]);            }        }    }    return 0;}


 

 

原创粉丝点击