BZOJ 3224 普通平衡树

AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=3224

平衡树的模板题,Splay操作可以让平均复杂度降到log(n)。

插入,即二叉搜索树的插入

删除,先Splay要删除的节点,然后将左右子树合并

前驱后继都可以直接用二叉搜索树的功能。

查询数的排名的时候,只需要Splay这个数,然后求左子树的节点个数就好了。

查询排名第k的时候,需要发挥神奇的记录存在这个节点下的子树上的节点个数的属性,然后利用搜索二叉树的方法,进行二分搜索,判断位置。

我的代码很长...但是我觉得还是蛮好看的恩...因为没有看过别人的模板...

数据结构题真的调好久啊,好久啊

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=100010;

inline int in(){
    int x=0,flag=1;char ch=getchar();
    while((ch>'9' || ch<'0') && ch!='-') ch=getchar();
    if(ch=='-') flag=-1,ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*flag;/*忘记乘flag*/
}

int cnt;

struct Node{
    int data,sum,cot;
    int l,r,f;
}s[maxn];

inline void updata(int a){
    s[a].sum=s[s[a].l].sum+s[s[a].r].sum+s[a].cot;
}

inline void up_updata(int a){
    while(a){
        s[a].sum=s[s[a].l].sum+s[s[a].r].sum+s[a].cot;
        a=s[a].f;
    }
}

void print(int Root){
    if(!Root) return;
    print(s[Root].l);
    for(int i=1;i<=s[Root].cot;i++)
        printf("%d ",s[Root].data);
    print(s[Root].r);
}

void zig(int x){
    int y=s[x].f;
    
    s[y].l=s[x].r;
    if(s[x].r) s[s[x].r].f=y;
    
    s[x].f=s[y].f;
    if(s[y].f){
        if(y==s[s[y].f].l) s[s[y].f].l=x;
        else s[s[y].f].r=x;
    }
    
    s[y].f=x,s[x].r=y;
    updata(y),updata(x);/*这里顺序反过一次*/
}

void zag(int x){
    int y=s[x].f;
    
    s[y].r=s[x].l;
    if(s[x].l) s[s[x].l].f=y;
    
    s[x].f=s[y].f;
    if(s[y].f){
        if(y==s[s[y].f].l) s[s[y].f].l=x;
        else s[s[y].f].r=x;
    }
    
    s[y].f=x,s[x].l=y;
    updata(y),updata(x);
}

void Splay(int x,int &Root){
    int y;
    
    while(s[x].f){
        y=s[x].f;
        if(!s[y].f){
            if(x==s[y].l) zig(x);
            else zag(x);
            break;
        }
        if(x==s[y].l){
            if(y==s[s[y].f].l) zig(y),zig(x);
            else zig(x),zag(x);
        }
        else{
            if(y==s[s[y].f].r) zag(y),zag(x);
            else zag(x),zig(x);
        }
    }
    
    Root=x;
}

int Find(int x,int &Root){
    int p=Root;
    while(p){
        if(s[p].data==x) break;
        else if(s[p].data>x) p=s[p].l;
        else p=s[p].r;
    }
    if(!p) return 0;
    Splay(p,Root);
    return p;
}

void Insert(int x,int &Root){
    int p=Root;
    if(!p){
        Root=++cnt,s[cnt].f=0,s[cnt].data=x,s[cnt].cot=s[cnt].sum=1;
        return;
    }
    while(p){
        if(s[p].data==x){
            s[p].cot++;up_updata(p)/*这里打成cnt*/;break;
        }
        else if(s[p].data>x){
            if(s[p].l)
                p=s[p].l;
            else{
                s[p].l=++cnt,s[cnt].f=p,s[cnt].data=x,s[cnt].cot=1,up_updata(cnt);
                break;
            }
        }
        else{
            if(s[p].r)
                p=s[p].r;
            else{
                s[p].r=++cnt,s[cnt].f=p,s[cnt].data=x,s[cnt].cot=1,up_updata(cnt);
                break;
            }
        }
    }
}

int find_max(int &Root){
    int p=Root;
    while(s[p].r) p=s[p].r;
    Splay(p,Root);
    return p;
}


int find_min(int &Root){
    int p=Root;
    while(s[p].l) p=s[p].l;
    Splay(p,Root);
    return p;
}

int pre(int x,int &Root){
    int p=Root,last=p;
    while(p)
        if(s[p].data>=x) p=s[p].l;
        else
            last=p,p=s[p].r;
    return last;
}

int las(int x,int &Root){
    int p=Root,last=p;
    while(p)
        if(s[p].data<=x) p=s[p].r;
        else
            last=p,p=s[p].l;
    return last;
}

int Union(int &Root1,int Root2){
    if(!Root1) {s[Root2].f=0;return Root2;}
    if(!Root2) {s[Root1].f=0;return Root1;}
    int p=find_max(Root1);
    s[p].r=Root2;
    s[Root2].f=p;
    updata(p);
    return p;
}

void Delete(int x,int &Root){
    int p=Find(x,Root);
    if(s[p].cot==1)
        Root=Union(s[p].l,s[p].r);
    else
        s[p].cot--,s[p].sum--;
}

int get_rank(int x,int &Root){
    int p=Find(x,Root);
    return s[s[p].l].sum;
}

int get_num(int k,int Root){
    int p=Root;
    while(p){
        if(k<=s[s[p].l].sum) p=s[p].l;
        else{
            k-=s[s[p].l].sum;
            if(k<=s[p].cot)
                return s[p].data;
            else
                k-=s[p].cot,p=s[p].r;
        }
    }
    return 0;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("3224.in","r",stdin);
    freopen("3224.out","w",stdout);
#endif

    int kase=in(),ord,x,Root=0;

    while(kase--){
        ord=in();x=in();
        if(ord==1)
            Insert(x,Root);
        else if(ord==2)
            Delete(x,Root);
        else if(ord==3)
            printf("%d\n",get_rank(x,Root)+1);
        else if(ord==4)
            printf("%d\n",get_num(x,Root));
        else if(ord==5)
            printf("%d\n",s[pre(x,Root)].data);
        else
            printf("%d\n",s[las(x,Root)].data);
        //print(Root);putchar('\n');
    }

    return 0;
}
View Code

附送这题的make_data,虽然做的有点丑吧...但是应该不会造出错误的数据...

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<algorithm>

using namespace std;

int rec[10010];

bool cmp(const int a,const int b){
    //return a<b;
    //return cos(a)<sin(b);
    return rand()%10<rand()%10;
}

int main(){
    freopen("3224.in","w",stdout);
    
    srand(time(0));
    
    int cnt=0,t=rand()%1+100000;
    
    printf("%d\n",t);
    
    for(int i=1;i<=t;i++){
        int ord=rand()%6+1,x=rand()%100000+1;
        if(cnt<=1) ord=1;
        if(ord==1){
            rec[++cnt]=x;
            printf("1 %d\n",x);
        }
        else if(ord==2){
            printf("2 %d\n",rec[cnt]);rec[cnt--]=0;
        }
        else if(ord==3){
            printf("3 %d\n",rec[(rand()%cnt)+1]);
        }
        else if(ord==4)
            printf("4 %d\n",rand()%cnt+1);
        else if(ord==5){
            if(cnt>2000)
                sort(rec+1,rec+cnt+1,cmp);
            printf("5 %d\n",rec[(rand()%cnt)+1]+1);
        }
        else if(ord==6){
            //sort(rec+1,rec+cnt+1,cmp);
            printf("6 %d\n",rec[(rand()%cnt)+1]-1);
        }
    }
    
    return 0;
}
View Code

对拍加油啦...

posted @ 2015-12-20 19:31  诚叙  阅读(400)  评论(0编辑  收藏  举报