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

73 篇文章 21 订阅
56 篇文章 0 订阅

 

 

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;
}


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值