zoukankan      html  css  js  c++  java
  • FHQ-Treap学习笔记

    FHQ-Treap学习笔记

    Wogua_boy

    感谢洛谷大佬远航之曲提供的学习资料~

    FHQ-Treap是由清华大学的超级大佬范浩强发明的,一种实现简单的,可以支持所有Splay操作的的Treap树。

    它只需要两个基础操作,就可以达到splay的所有功能。

    split

    它的主要思想就是把一个Treap分成两个。

    split操作有两种类型,一种是按照权值分配,一种是按照前k个分配。

    第一种就是把所有小于k的权值的节点分到一棵树中,第二种是把前k个分到一个树里。

    对于我们遍历每一个点:

    假如它的权值小于k,那么它的所有左子树,都要分到左边的树里,然后遍历它的右儿子。

    假如它的权值大于k,那么它的所有右子树,都要分到右边的树里,然后遍历它的左儿子。

    因为它的最多操作次数就是一直分到底,效率就是(O(logn))

    merge

    这个就是把两个Treap合成一个,保证第一个的权值小于第二个。

    几个基本的平衡树操作

    1. insert

      插入一个权值为v的点,把树按照v的权值split成两个,再按照顺序merge回去。

    2. del

      删除权值为v的点,把树按照v分成两个a,b,再把a按照v-1分成c,d。

      把c的两个子儿子merge起来,再merge(merge(c,d),b)

    3. precursor

      找前驱,把root按v-1 split成x和y,在x里面找最大值。

    4. successor

      找后继,把root按v split成x和y,在y里面找最小值。

    5. rank

      把root按v-1 split成x和y,排名是x的size。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+100;
    int ch[maxn][2];
    int val[maxn];//本身权值 
    int pri[maxn];//随机权值 
    int sz[maxn];//子树大小 
    int tot;
    void up (int x) {
    	sz[x]=1+sz[ch[x][0]]+sz[ch[x][1]];
    }
    int newNode (int v) {
    	sz[++tot]=1;
    	val[tot]=v;
    	pri[tot]=rand();//可以改成自定义随机函数
    	return tot; 
    }
    int merge (int x,int y) {
    	if (!x||!y) return x+y;
    	if (pri[x]<pri[y]) {
    		ch[x][1]=merge(ch[x][1],y);
    		up(x);
    		return x;
    	}
    	else {
    		ch[y][0]=merge(x,ch[y][0]);
    		up(y);
    		return y;
    	}
    }
    void split (int u,int k,int &x,int &y) {
    	if (!u) x=y=0;
    	else {
    		if (val[u]<=k) {
    			x=u;
    			split(ch[u][1],k,ch[u][1],y);
    		}
    		else {
    			y=u;
    			split(ch[u][0],k,x,ch[u][0]);
    		}
    		up(u);
    	}
    }
    int kth (int u,int k) {
    	while (1) {
    		if (k<=sz[ch[u][0]]) {
    			u=ch[u][0];
    		}
    		else if (k==sz[ch[u][0]]+1) {
    			return u;
    		}
    		else {
    			k-=sz[ch[u][0]]+1;
    			u=ch[u][1];
    		}
    	}
    }
    int x,y,z,rt;
    int main () {
    	srand((unsigned)time(NULL));
    	int _;
    	scanf("%d",&_);
    	while (_--) {
    		int op,tt;
    		scanf("%d%d",&op,&tt);
    		if (op==1) {
                //插入x
    			split(rt,tt,x,y);
    			rt=merge(merge(x,newNode(tt)),y);
    		}
    		else if (op==2) {
                //删除x
    			split(rt,tt,x,z);
    			split(x,tt-1,x,y);
    			y=merge(ch[y][0],ch[y][1]);
    			rt=merge(merge(x,y),z);
    		}
    		else if (op==3) {
                //查询x的排名
    			split(rt,tt-1,x,y);
    			printf("%d
    ",sz[x]+1);
    			rt=merge(x,y);
    		}
    		else if (op==4) {
                //查询排名x的数
    			printf("%d
    ",val[kth(rt,tt)]);
    		}
    		else if (op==5) {
                //求x的前驱
    			split(rt,tt-1,x,y);
    			printf("%d
    ",val[kth(x,sz[x])]);
    			rt=merge(x,y);
    		}
    		else {
                //求x的后继
    			split(rt,tt,x,y);
    			printf("%d
    ",val[kth(y,1)]);
    			rt=merge(x,y);
    		}
    	}
    }
    
  • 相关阅读:
    块设备驱动框架分析(一)
    LIN总线协议
    LCD驱动分析(三)时序分析
    str_shuffle — 随机打乱一个字符串
    str_replace — 子字符串替换
    str_repeat — 重复一个字符串
    str_pad — 使用另一个字符串填充字符串为指定长度
    str_getcsv — 解析 CSV 字符串为一个数组
    ltrim — 删除字符串开头的空白字符(或其他字符)
    lcfirst — 使一个字符串的第一个字符小写
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14645666.html
Copyright © 2011-2022 走看看