zoukankan      html  css  js  c++  java
  • Treap与fhq_Treap模板(支持内存回收)

    1.普通Treap

    通过左右旋来维护堆的性质

    左右旋是不改变中序遍历的

    这里有几点要注意一下:

      (1).由于写了内存回收,在 newnode 的时候要 memset 一下这个节点,因为可能被用过

      (2).在删除时要这么写 : 如果只有小于等于1个儿子就直接删

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<cstdio>
    #include<cmath>
    #include<ctime>
    using namespace std;
     
    const int MAXN = 100100, inf = 0x7fffffff;
     
    struct Node{
        int ch[2];
        int val, prio;
        int cnt, siz;
    //  Node(){ch[0] = ch[1] = val = cnt = siz = 0;}
    }t[MAXN];
     
     
    int n;
    int root, pool_cur, delpool[MAXN], delcur;
     
    void init();
    int newnode(int val);
    void delnode(int cur);
    void pushup(int cur);
    void rotate(int &cur, int d);
    void Insert(int &cur, int val);
    void Remove(int &cur, int val);
    int getpre(int val);
    int getnxt(int val);
    int getrankbyval(int cur, int val);
    int getvalbyrank(int cur, int rank);
     
    int main() {
        srand(time(NULL));
        scanf("%d", &n);
        int opt, x;
        init();
        for(int i = 1; i <= n; ++i) {
            scanf("%d%d", &opt, &x);
            switch(opt) {
                case 1:{
                    Insert(root, x);
                    break;
                }
                case 2:{
                    Remove(root, x);
                    break;
                }
                case 3:{
                    printf("%d
    ", getrankbyval(root, x) - 1);
                    break;
                }
                case 4:{
                    printf("%d
    ", getvalbyrank(root, x + 1));
                    break;
                }
                case 5:{
                    printf("%d
    ", getpre(x));
                    break;
                }
                case 6:{
                    printf("%d
    ", getnxt(x));
                    break;
                }
            }
        }
        return 0;
    }
     
    void init() {
        newnode(-inf);
        newnode(inf);
        root = 1;
        t[1].ch[1] = 2;
        pushup(root);
        return;
    }
    
    inline void delnode(int cur) {
        delpool[++delcur] = cur;
        return;
    }
     
    int newnode(int val) {
        int cur = (delcur ? delpool[delcur--] : ++pool_cur);
        memset(t + cur, 0, sizeof(Node));
        t[cur].siz = t[cur].cnt = 1;
        t[cur].prio = rand();
        t[cur].val = val;
        return cur;
    }
     
    void pushup(int cur) {
        t[cur].siz = t[t[cur].ch[0]].siz + t[t[cur].ch[1]].siz + t[cur].cnt;
        return;
    }
     
    void rotate(int &cur, int d) {
        int u = t[cur].ch[d];
        t[cur].ch[d] = t[u].ch[d^1];
        t[u].ch[d^1] = cur;
        t[u].siz = t[cur].siz;
        pushup(cur);
        cur = u;
        return;
    }
     
    void Insert(int &cur, int val) {
        if(cur == 0) {
            cur = newnode(val);
            return;
        }
        if(t[cur].val == val) {
            ++t[cur].cnt;
            pushup(cur);
            return;
        }
        int d = t[cur].val < val;
        Insert(t[cur].ch[d], val);
        pushup(cur);
        if(t[t[cur].ch[d]].prio < t[cur].prio) rotate(cur, d);
        return;
    }
     
    void Remove(int &cur, int val) {
        if(!cur) return;
        if(t[cur].val == val) {
            int o = cur;
            if(t[cur].cnt > 1) {
                --t[cur].cnt;
            } else {
                if(!t[cur].ch[0]) {
                    cur = t[cur].ch[1];
                    delnode(o);
                } else if(!t[cur].ch[1]) {
                    cur = t[cur].ch[0];
                	delnode(o);
                } else {
                    int d = t[t[cur].ch[0]].prio < t[t[cur].ch[1]].prio;
                    rotate(cur, d ^ 1);
                    Remove(t[cur].ch[d], val);
                }
            }
            pushup(cur);
        } else {
            int d = t[cur].val < val;
            Remove(t[cur].ch[d], val);
        }
        pushup(cur);
        return;
    }
     
    int getpre(int val) {
        int ans = 1;
        int cur = root;
        while(cur) {
            if(val == t[cur].val) {
                if(t[cur].ch[0] > 0) {
                    cur = t[cur].ch[0];
                    while(t[cur].ch[1] > 0) cur = t[cur].ch[1];
                    ans = cur;
                }
                break;
            }
            if(t[cur].val < val and t[cur].val > t[ans].val) ans = cur;
            cur = t[cur].val > val ? t[cur].ch[0] : t[cur].ch[1];
        }
        return t[ans].val;
    }
     
    int getnxt(int val) {
        int ans = 2;
        int cur = root;
        while(cur) {
            if(val == t[cur].val) {
                if(t[cur].ch[1] > 0) {
                    cur = t[cur].ch[1];
                    while(t[cur].ch[0] > 0) cur = t[cur].ch[0];
                    ans = cur;
                }
                break;
            }
            if(t[cur].val > val and t[cur].val < t[ans].val) ans = cur;
            cur = t[cur].val > val ? t[cur].ch[0] : t[cur].ch[1];
        }
        return t[ans].val;
    }
     
    int getrankbyval(int cur, int val) {
        if(!cur) return 0;
        if(val == t[cur].val) return t[t[cur].ch[0]].siz + 1;
        return t[cur].val > val ? getrankbyval(t[cur].ch[0], val) : (getrankbyval(t[cur].ch[1], val) + t[t[cur].ch[0]].siz + t[cur].cnt);
    }
     
    int getvalbyrank(int cur, int rank) {
        if(!cur) return 0;
        if(t[t[cur].ch[0]].siz >= rank) return getvalbyrank(t[cur].ch[0], rank);
        if(t[t[cur].ch[0]].siz + t[cur].cnt >= rank) return t[cur].val;
        return getvalbyrank(t[cur].ch[1], rank - t[t[cur].ch[0]].siz - t[cur].cnt);
    }

    2.fhq_Treap (非旋 Treap )

    通过 Split 和 Merge 操作来维护平衡树

    (1) 用 fhq_Treap 实现普通 Treap 支持的操作

      Split :

        把以 cur 为根的树的前 k 个元素分离开

        返回值为分离后的两根

    pair<int, int> Split(int cur, int k) {
    	if(!cur or !k) return make_pair(0, cur);
    	pair<int, int> res;
    	if(t[lson].siz >= k) {
    		res = Split(lson, k);
    		lson = res.second;
    		pushup(cur);
    		res.second = cur;
    	} else {
    		res = Split(rson, k - t[lson].siz - 1);
    		rson = res.first;
    		pushup(cur);
    		res.first = cur;
    	}
    	return res;
    }
    

        进入右子树,则一定选当前节点,将它作为分离后左边那棵树的根

        进入左子树,则一定不选当前节点,将它作为分离后的右边那棵树的根

      Merge : 

        像可并堆那样进行合并

        这样来满足堆性质

    int Merge(int x, int y) {
    	if(!x) return y; if(!y) return x;
    	if(t[x].prio < t[y].prio) {
    		t[x].ch[1] = Merge(t[x].ch[1], y);
    		pushup(x);
    		return x;
    	} else {
    		t[y].ch[0] = Merge(x, t[y].ch[0]);
    		pushup(y);
    		return y;
    	}
    }

    这里写一种比较清奇的 getrank , 返回所有小于 val 的元素个数

    很好用的

    int getrnk(int cur, int val)  {
    	if(!cur) return 0;
    	return val <= t[cur].val ? getrnk(lson, val) : (getrnk(rson, val) + t[lson].siz + 1);
    }

    加哨兵总是挂,最后就没加 = =

    好像也不用加

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<cstdio>
    #include<cmath>
    #include<ctime>
    #define lson t[cur].ch[0]
    #define rson t[cur].ch[1]
    using namespace std;
     
    const int MAXN = 100001;
     
    struct Node{
        int ch[2], siz, prio, val;
    }t[MAXN];
    int n, Root, poolcur;
    int delpool[MAXN], delcur;
     
    inline void pushup(int cur) {
        t[cur].siz = t[lson].siz + t[rson].siz + 1;
        return;
    }
    inline void delnode(int cur) {
    	delpool[++delcur] = cur;
    	return;
    }
    inline int newnode(int val) {
        register int cur = (delcur ? delpool[delcur--] : ++poolcur);
        memset(t + cur, 0, sizeof(Node));
        t[cur].val = val;
        t[cur].siz = 1;
        t[cur].prio = rand();
        return cur;
    }
    pair<int, int> Split(int cur, int k) {
        if(!cur or !k) return make_pair(0, cur);
        pair<int, int> res;
        if(t[lson].siz >= k) {
            res = Split(lson, k);
            lson = res.second;
            pushup(cur);
            res.second = cur;
        } else {
            res = Split(rson, k - t[lson].siz - 1);
            rson = res.first;
            pushup(cur);
            res.first = cur;
        }
        return res;
    }
    int Merge(int x, int y) {
        if(!x) return y; if(!y) return x;
        if(t[x].prio < t[y].prio) {
            t[x].ch[1] = Merge(t[x].ch[1], y);
            pushup(x);
            return x;
        } else {
            t[y].ch[0] = Merge(x, t[y].ch[0]);
            pushup(y);
            return y;
        }
    }
    int getrnk(int cur, int val)  {
        if(!cur) return 0;
        return val <= t[cur].val ? getrnk(lson, val) : (getrnk(rson, val) + t[lson].siz + 1);
    }
    int findkth(int k) {
        pair<int, int> x = Split(Root, k - 1);
        pair<int, int> y = Split(x.second, 1);
        int ans = t[y.first].val;
        Root = Merge(Merge(x.first, y.first), y.second);
        return ans;
    }
    int getpre(int val) {
        register int k = getrnk(Root, val);
        return findkth(k);
    }
    int getnxt(int val) {
        register int k = getrnk(Root, val + 1);
        return findkth(k + 1);
    }
    void Insert(int val) {
        pair<int, int> x = Split(Root, getrnk(Root, val));
        Root = Merge(Merge(x.first, newnode(val)), x.second);
        return;
    }
    void Remove(int val) {
        register int k = getrnk(Root, val);
        pair<int, int> x = Split(Root, k);
        pair<int, int> y = Split(x.second, 1);
        delnode(y.first);
        Root = Merge(x.first, y.second);
        return;
    }
    inline int rd() {
        register int x = 0;
        register char c = getchar();
        register bool f = false;
        while(!isdigit(c)) {
            if(c == '-') f = true;
            c = getchar();
        }
        while(isdigit(c)) {
            x = x * 10 + c - 48;
            c = getchar();
        }
        return f ? -x : x;
    }
     
    int main() {
        srand(time(NULL));
        memset(t, 0, sizeof(Node)); 
        n = rd();
        int opt, x;
        while(n--) {
            opt = rd(); x = rd();
            switch(opt) {
                case 1: {
                    Insert(x);
                    break;
                }
                case 2: {
                    Remove(x);
                    break;
                }
                case 3: {
                    printf("%d
    ", getrnk(Root, x) + 1);
                    break;
                }
                case 4: {
                    printf("%d
    ", findkth(x));
                    break;
                }
                case 5: {
                    printf("%d
    ", getpre(x));
                    break;
                }
                case 6: {
                    printf("%d
    ", getnxt(x));
                    break;
                }
            }
        }
        return 0;
    }
    

    (2) 用 fhq_Treap 实现 Splay 支持的区间操作

      fhq_Treap是支持拼接子树的,所以也能够很好的支持区间操作

      要对区间 [ l, r ] 进行操作,就先把前 r 个元素 Split 出来,再将前 l - 1 个元素 Split 出来,这样就得到了区间 [ l, r ] 的一棵Treap

      之后进行想要的操作即可

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<cstdio>
    #include<cmath>
    #include<ctime>
    #define lson t[cur].ch[0]
    #define rson t[cur].ch[1]
    using namespace std;
    
    const int MAXN = 100001;
    
    struct Node{
    	int ch[2], siz, val, prio;
    	bool rvrs;
    	Node(){ch[0] = ch[1] = siz = val = 0; rvrs = false;}
    }t[MAXN];
    int n, m, Root, poolcur;
    
    inline int rd() {
    	register int x = 0;
    	register char c = getchar();
    	register bool f = false;
    	while(!isdigit(c)) {
    		if(c == '-') f = true;
    		c = getchar();
    	}
    	while(isdigit(c)) {
    		x = x * 10 + c - 48;
    		c = getchar();
    	}
    	return f ? -x : x;
    }
    inline void pushup(int cur) {
    	t[cur].siz = t[lson].siz + t[rson].siz + 1;
    	return;
    }
    inline void pushdown(int cur) {
    	if(cur && t[cur].rvrs) {
    		t[cur].rvrs = false;
    		swap(lson, rson);
    		t[lson].rvrs ^= 1;
    		t[rson].rvrs ^= 1;
    	}
    	return;
    }
    inline int newnode(int val) {
    	register int cur = ++poolcur;
    	t[cur].val = val;
    	t[cur].siz = 1;
    	t[cur].prio = rand();
    	t[cur].rvrs = false;
    	return cur;
    }
    pair<int, int> Split(int cur, int k) {
    	if(!cur or !k) return make_pair(0, cur);
    	pushdown(cur); pair<int, int> res;
    	if(t[lson].siz >= k) {
    		res = Split(lson, k);
    		lson = res.second;
    		pushup(cur);
    		res.second = cur;
    	} else {
    		res = Split(rson, k - t[lson].siz - 1);
    		rson = res.first;
    		pushup(cur);
    		res.first = cur;
    	}
    	return res;
    }
    int Merge(int x, int y) {
    	pushdown(x); pushdown(y);
    	if(!x) return y; if(!y) return x;
    	if(t[x].prio < t[y].prio) {
    		t[x].ch[1] = Merge(t[x].ch[1], y);
    		pushup(x);
    		return x;
    	} else {
    		t[y].ch[0] = Merge(x, t[y].ch[0]);
    		pushup(y);
    		return y;
    	}
    }
    int getrnk(int cur, int val) {
    	if(!cur) return 0;
    	return val <= t[cur].val ? getrnk(lson, val) : (getrnk(rson, val) + t[lson].siz + 1);
    }
    void Insert(int val) {
    	pair<int, int> x = Split(Root, getrnk(Root, val));
    	Root = Merge(Merge(x.first, newnode(val)), x.second);
    	return;
    }
    void Reverse(int l, int r) {
    	pair<int, int> x = Split(Root, r);
    	pair<int, int> y = Split(x.first, l - 1);
    	t[y.second].rvrs ^= 1;
    	Root = Merge(Merge(y.first, y.second), x.second);
    	return;
    }
    void Recycle(int cur) {
    	if(!cur) return;
    	pushdown(cur);
    	if(lson) Recycle(lson);
    	if(t[cur].val > 0 and t[cur].val <= n) printf("%d ", t[cur].val);
    	if(rson) Recycle(rson);
    	return;
    }
    inline void init() {
    	t[1].val = t[1].siz = 1;
    	Root = 1; poolcur = 1;
    	t[1].prio = rand();
    	return;
    }
    
    int main() {
    	srand(time(NULL));
    	n = rd(); m = rd();
    	init();
    	for(int i = 2; i <= n; ++i) Insert(i);
    	int l, r;
    	while(m--) {
    		l = rd(); r = rd();
    		Reverse(l, r);
    	}
    	Recycle(Root);
    	putchar('
    ');
    	return 0;
    }
    

    Update: 

      在写 bzoj1500 时有些奇怪的疑惑: Split 出来之后再 Merge 回去还是原来的树吗?区间反转的 tag 给当前根打上之后再接回去不会 GG 吗?

      显然,它还是原来的树,reverse 之后也并不会 GG . 当原来的 x.first 回到它应该的位置后,x.second 整棵子树靠近 x.first 一侧的 tag 也已经下放至更深一层了


    禁止诸如开发者知识库/布布扣/码迷/学步园/马开东等 copy 他人博文乃至博客的网站转载 ,用户转载请注明出处:https://www.cnblogs.com/xcysblog/
  • 相关阅读:
    使用Xshell为xftp开ssh通道代理
    linux下查找svn的相关目录的命令
    linux服务器A远程连接服务器B的mysql及1045错误
    怎样下载带权限认证的文件?
    Vue项目打包部署总结
    Vue项目打包压缩:让页面更快响应
    axios请求失败自动重发
    可用的后台管理系统
    vue组件间方式总结
    非脚手架创建vue项目,并使用webpack打包
  • 原文地址:https://www.cnblogs.com/xcysblog/p/9064774.html
Copyright © 2011-2022 走看看