• P3369 【模板】普通平衡树


    splay

    splay与他的解析

    二叉搜索树

    我们搞一棵树,保证左子树所有点的权值比父亲小,右子树所有点权值比父亲大

    显然这个玩意可以快速查询一个数存不存在,排名啦啥的

    插入的时候直接顺序造节点,删除的时候,断开重连是件很愚蠢的事情

    应该把删除节点和他右子树最左边那个或者左子树最右边那个交换,销毁它

    这样有什么问题呢?

    如果坑逼出题人给你搞成了链,直接起飞成$ O(n)$了

    这不就挂了

    那么该怎么搞呢

    伸展树splay出现了

    splay,旋转,自我调整,

    旋转

    捕获.PNG

    本图片引用自liuzhangfeiabc课件

    我们可以看到,转x,就是让f变成x的右儿子,x的右儿子变成f的左儿子,x的右儿子变成f,x代替f

    void ro(int x){
    	int f=po[x].fa;
    	int gf=po[f].fa;
    	int xp=ident(x);
    	int fp=ident(f);
    	connect(po[x].son[xp^1],f,xp);
    	connect(f,x,xp^1);
    	connect(x,gf,fp);
    	update(f);
    	update(x);
    }
    

    但是出题人还能接着卡你

    怎么办呢,我们一次转俩,直接强行链改树

    splay

    void splay(int x,int to){
    	to=po[to].fa;
    	while(po[x].fa!=to){
    		int f=po[x].fa;
    		if(po[f].fa==to) ro(x);
    		else if(ident(x)==ident(f)) ro(f),ro(x);
    		else ro(x),ro(x);
    	}
    }.
    

    这又是在干什么呢

    我们可以把一个节点移到你想去的任何位置如果爹,爹的爹和儿子共线,就要先转爹,不然就转两次儿子,就可以成功的压成树了

    更具体的操作

    插入 这里没什么大坑,就是记得最后splay一下

    void insert(int x){
    	int now=po[0].son[1];
    	if(now==0){
    		creat(x,0);
    		po[0].son[1]=tot;
    	}else{
    		while(1){
    			po[now].sum++;
    			if(po[now].val==x){
    				po[now].cnt++;
    				splay(now,po[0].son[1]);
    				return ;
    			}
    			int nex=x<po[now].val?0:1;
    			if(!po[now].son[nex]){
    				int p=creat(x,now);
    				po[now].son[nex]=p;
    				splay(p,po[0].son[1]);
    				return ;
    			}
    			now=po[now].son[nex];
    		}
    	}
    }
    

    寻找排名

    也很好理解,记得splay

    int find(int x){
    	int now=po[0].son[1];
    	while(1){
    		if(!now) return 0;
    		if(po[now].val==x) {
    			splay(now,po[0].son[1]);
    			return now;
    		}
    		int nex=x<po[now].val?0:1;
    		now=po[now].son[nex];
    	}
    }
    

    删除

    还是很好解决的,先找到它,如果它是叶子,直接删掉,如果它没有左儿子的,就直接把右儿子接上去,如果都有,就找它右子树最左的那个,splay进行交换,销毁

    void del(int x){
    	int pos=find(x);
    	if(!pos) return ;
    	if(po[pos].cnt>1){
    		po[pos].cnt--;
    		po[pos].sum--;
    		return ;
    	}else{
    		if(!po[pos].son[0]&&!po[pos].son[1]) {
    			po[0].son[1]=0;
    			return ;
    		}else if(!po[pos].son[0]){
    			po[0].son[1]=po[pos].son[1];
    			po[po[0].son[1]].fa=0;
    			return ;
    		} else{
    			int le=po[pos].son[0];
    			while(po[le].son[1]) le=po[le].son[1];
    			splay(le,po[pos].son[0]);
    			connect(po[pos].son[1],le,1);
    			connect(le,0,1);
    			update(le);
    		}
    	}
    }
    

    按照排名找数

    同理

    找前缀

    记得一直取max

    后缀

    和前缀反着

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cstring>
    #define int long long
    using namespace std;
    const int maxn=1e6+10;
    const int mod=10007;
    const int inf=1e9+10;
    struct p{
    	int fa;
    	int son[2];
    	int val;
    	int cnt;
    	int sum;
    }po[maxn];
    int tot;
    int n,opt;int x;
    int ps;
    inline int read(){
        int res=0,k=1;
        char c=getchar();
        while(!isdigit(c)){
            if(c=='-')k=-1;
            c=getchar();
        }
        while(isdigit(c)){
            res=(res<<1)+(res<<3)+c-48;
            c=getchar();
        }
        return res*k;
    }
    void update(int x){
    	po[x].sum=po[po[x].son[0]].sum+po[po[x].son[1]].sum+po[x].cnt;
    }
    int ident(int x){
    	return po[po[x].fa].son[0]==x?0:1;
    }
    void connect(int x,int fa,int s){
    	po[fa].son[s]=x;
    	po[x].fa=fa;
    }
    void ro(int x){
    	int f=po[x].fa;
    	int gf=po[f].fa;
    	int xp=ident(x);
    	int fp=ident(f);
    	connect(po[x].son[xp^1],f,xp);
    	connect(f,x,xp^1);
    	connect(x,gf,fp);
    	update(f);
    	update(x);
    }
    void splay(int x,int to){
    	to=po[to].fa;
    	while(po[x].fa!=to){
    		int f=po[x].fa;
    		if(po[f].fa==to) ro(x);
    		else if(ident(x)==ident(f)) ro(f),ro(x);
    		else ro(x),ro(x);
    	}
    }
    int creat(int val,int f){
    	++tot;
    	po[tot].fa=f;
    	po[tot].sum=po[tot].cnt=1;
    	po[tot].val=val;
    	return tot;
    }
    void insert(int x){
    	int now=po[0].son[1];
    	if(now==0){
    		creat(x,0);
    		po[0].son[1]=tot;
    	}else{
    		while(1){
    			po[now].sum++;
    			if(po[now].val==x){
    				po[now].cnt++;
    				splay(now,po[0].son[1]);
    				return ;
    			}
    			int nex=x<po[now].val?0:1;
    			if(!po[now].son[nex]){
    				int p=creat(x,now);
    				po[now].son[nex]=p;
    				splay(p,po[0].son[1]);
    				return ;
    			}
    			now=po[now].son[nex];
    		}
    	}
    }
    int find(int x){
    	int now=po[0].son[1];
    	while(1){
    		if(!now) return 0;
    		if(po[now].val==x) {
    			splay(now,po[0].son[1]);
    			return now;
    		}
    		int nex=x<po[now].val?0:1;
    		now=po[now].son[nex];
    	}
    }
    void del(int x){
    	int pos=find(x);
    	if(!pos) return ;
    	if(po[pos].cnt>1){
    		po[pos].cnt--;
    		po[pos].sum--;
    		return ;
    	}else{
    		if(!po[pos].son[0]&&!po[pos].son[1]) {
    			po[0].son[1]=0;
    			return ;
    		}else if(!po[pos].son[0]){
    			po[0].son[1]=po[pos].son[1];
    			po[po[0].son[1]].fa=0;
    			return ;
    		} else{
    			int le=po[pos].son[0];
    			while(po[le].son[1]) le=po[le].son[1];
    			splay(le,po[pos].son[0]);
    			connect(po[pos].son[1],le,1);
    			connect(le,0,1);
    			update(le);
    		}
    	}
    }
    int rak(int x){
    	int now=po[0].son[1];
    	int ans=0;
    	while(1){
    		if(po[now].val==x) {
    	//	splay(now,po[0].son[1]);
    		 ans+=po[po[now].son[0]].sum+1;
    		 splay(now,po[0].son[1]);;
    		 return ans;
    		}
    		int nex=x<po[now].val?0:1;
    		if(nex==1) ans =ans+po[po[now].son[0]].sum+po[now].cnt;
    		now=po[now].son[nex];
    	}
    }
    int kth(int x){
    	int now=po[0].son[1];
    	while(1){
    		int re=po[now].sum-po[po[now].son[1]].sum;
    		if(po[po[now].son[0]].sum<x&&x<=re){
    			return po[now].val;
    		}
    		if(x<re) now=po[now].son[0];
    		else now =po[now].son[1],x-=re;
    	}
    }
    int lower(int x){
    	int now=po[0].son[1];
    	int ans=-inf;
    	while(now){
    		if(po[now].val<x) ans=max(ans,po[now].val);
    		int nex=x<=po[now].val?0:1;//等于也要往左走 
    		now=po[now].son[nex];
    	}
    	return ans;
    }
    int upper(int x){
    	int now=po[0].son[1];
    	int ans=inf;
    	while(now){
    		if(po[now].val>x) ans=min(ans,po[now].val);
    		int nex=x<po[now].val?0:1;
    		now=po[now].son[nex];
    	}
    	return ans;
    }
    signed main(){
    	n=read();
    	while(n--){
    		opt=read();
    		x=read();
    		if(opt==1) insert(x);
            else if(opt==2) del(x);
            else if(opt==3) printf("%d
    ",rak(x));
            else if(opt==4) printf("%d
    ",kth(x));
            else if(opt==5) printf("%d
    ",lower(x));
            else if(opt==6) printf("%d
    ",upper(x));
    	}
    	return 0;
    }
    
  • 相关阅读:
    mysql性能优化
    pymysql模块
    mysql数据表约束
    MySQL数据库
    IO模型
    8451
    8946531
    6783
    256213
    27822
  • 原文地址:https://www.cnblogs.com/For-Miku/p/15030626.html
Copyright © 2020-2023  润新知