zoukankan      html  css  js  c++  java
  • 【LG3835】可持久化平衡树

    【LG3835】可持久化平衡树

    题面

    洛谷

    解法一

    参考文章

    rope大法好

    (rope)基本操作:

    #include<ext/rope>
    using namespace __gnu_cxx;//rope的命名空间
    rope<type> R;
    R.push_back(a) //往后插入
    R.insert(pos,a)//在pos位置插入a,pos是一个迭代器。
    R.erase(pos,n)//在pos位置删除n个元素。
    R.replace(pos,x)//从pos开始替换成x
    R.substr(pos,x)//从pos开始提取x个。
    //多数时候定义rope用指针(方便可持久化) 所以上面的点多数时候要换成->
    

    再配合二分即可实现各种操作

    如何进行复制:

    rope<type>* R[1000];
    R[i] = new rope<type>(*R[v]);
    

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <ext/rope>
    #include <ext/pb_ds/assoc_container.hpp>
    using namespace std;
    using namespace __gnu_cxx; 
    inline int gi() {
        register int data = 0, w = 1;
        register char ch = 0;
        while (ch != '-' && (ch > '9' || ch < '0')) ch = getchar();
        if (ch == '-') w = -1 , ch = getchar();
        while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
        return w * data;
    } 
    #define MAX_N 500005 
    rope<int> *rop[MAX_N]; 
    int N; 
    int main () {  
        N = gi(); 
        rop[0] = new rope<int>(); 
        for (int i = 1; i <= N; i++) { 
        	int v = gi(), opt = gi(), x = gi(); 
        	rop[i] = new rope<int>(*rop[v]); 
        	if (opt == 1) rop[i]->insert(lower_bound(rop[i]->begin(), rop[i]->end(), x) - rop[i]->begin(), x); 
        	if (opt == 2) { 
        	    auto ite = lower_bound(rop[i]->begin(), rop[i]->end(), x); 
        	    if (ite != rop[i]->end() && *ite == x) rop[i]->erase(ite - rop[i]->begin(), 1); 
            } 
            if (opt == 3) 
            	printf("%d
    ", (int)(lower_bound(rop[i]->begin(), rop[i]->end(), x) - rop[i]->begin()) + 1); 
            if (opt == 4) printf("%d
    ", *(rop[i]->begin() + x - 1)); 
            if (opt == 5) { 
                auto ite = lower_bound(rop[i]->begin(), rop[i]->end(), x); 
                if (ite == rop[i]->begin() - 1) puts("-2147483647"); 
                else --ite, printf("%d
    ", *ite); 
            } 
            if (opt == 6) { 
                auto ite = upper_bound(rop[i]->begin(), rop[i]->end(), x); 
                if (ite == rop[i]->end()) puts("2147483647"); 
                printf("%d
    ", *ite); 
            } 
        } 
        return 0; 
    } 
    

    解法二

    用可持久化(trie)可以很方便地实现

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring> 
    #include <cmath> 
    #include <algorithm>
    #include <climits> 
    using namespace std;
    
    inline int gi() {
    	register int data = 0, w = 1;
    	register char ch = 0;
    	while (!isdigit(ch) && ch != '-') ch = getchar(); 
    	if (ch == '-') w = -1, ch = getchar();
    	while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
    	return w * data; 
    }
    
    const int MAX_N = 5e5 + 5; 
    const int T = 1e9; 
    struct Trie { int ch[2], size; } t[MAX_N << 5]; 
    int N, rt[MAX_N], tot;
    bool find(int o, int v) {
    	v += T; 
    	for (int i = 31; ~i; i--) {
    		int c = v >> i & 1;
    		if (!t[o].size || !o) return 0; 
    		o = t[o].ch[c]; 
    	} 
    	return 1; 
    } 
    void insert(int &x, int p, int v) {
    	x = ++tot; int o = x; 
    	v += T, t[o].size = t[p].size + 1; 
    	for (int i = 31; ~i; i--) { 
    		int c = v >> i & 1;
    		t[o].ch[c ^ 1] = t[p].ch[c ^ 1]; 
    		t[o].ch[c] = ++tot; 
    		o = t[o].ch[c], p = t[p].ch[c]; 
    		t[o].size = t[p].size + 1; 
    	} 
    } 
    void erase(int &x, int p, int v) { 
    	if (!find(p, v)) return (void)(x = p);
    	x = ++tot; int o = x; 
    	v += T, t[o].size = t[p].size - 1; 
    	for (int i = 31; ~i; i--) {
    		int c = v >> i & 1;
    		t[o].ch[c ^ 1] = t[p].ch[c ^ 1]; 
    		t[o].ch[c] = ++tot; 
    		o = t[o].ch[c], p = t[p].ch[c]; 
    		t[o].size = t[p].size - 1; 
    	} 
    } 
    int Kth(int o, int k) { 
    	long long res = -T; 
    	for (int i = 31; ~i; i--) {
    		int sz = t[t[o].ch[0]].size; 
    		if (k <= sz) o = t[o].ch[0]; 
    		else res += (1 << i), o = t[o].ch[1], k -= sz; 
    	}
    	return res; 
    } 
    int LR(int o, int v) { 
    	v += T; int res = 0; 
    	for (int i = 31; ~i; i--) { 
    		int c = v >> i & 1; 
    		if (c) res += t[t[o].ch[0]].size; 
    		o = t[o].ch[c];
    		if (!o || !t[o].size) return res; 
    	} 
    	return res; 
    }
    int UR(int o, int v) {
    	v += T; int res = 0; 
    	for (int i = 31; ~i; i--) { 
    		int c = v >> i & 1; 
    		if (!c) res += t[t[o].ch[1]].size; 
    		o = t[o].ch[c];
    		if (!o || !t[o].size) return res; 
    	} 
    	return res; 
    } 
    int Rnk(int o, int v) { return LR(o, v) + 1; } 
    
    signed main () {
    	N = gi(); 
    	rt[0] = ++tot; 
    	for (int i = 1; i <= N; i++) {
    		int v = gi(), op = gi(), x = gi();
    		if (op == 1) insert(rt[i], rt[v], x); 
    		if (op == 2) erase(rt[i], rt[v], x); 
    		if (op == 3) rt[i] = rt[v], printf("%d
    ", Rnk(rt[i], x));
    		if (op == 4) rt[i] = rt[v], printf("%d
    ", Kth(rt[i], x));
    		if (op == 5) {
    			rt[i] = rt[v];
    			int res = LR(rt[i], x);
    			if (!res) printf("%d
    ", -INT_MAX);
    			else printf("%d
    ", Kth(rt[i], res)); 
    		}
    		if (op == 6) {
    			rt[i] = rt[v]; 
    			int res = UR(rt[i], x);
    			if (!res) printf("%d
    ", INT_MAX);
    			else printf("%d
    ", Kth(rt[i], t[rt[i]].size - res + 1)); 
    		} 
    	} 
    	return 0; 
    } 
    
  • 相关阅读:
    MySQL创建数据库简单命令
    工作的本质是解决问题
    使用消息中间件时,如何保证消息仅仅被消费一次?
    缓存穿透了怎么办?
    MySQL 数据库的提速器-写缓存(Change Buffer)
    删库了,我们一定要跑路吗?
    做好一件事的三要素
    一分钟简单了解 JSON Web Token
    聊一聊 MySQL 中的数据编辑过程中涉及的两阶段提交
    聊一聊 MySQL 数据库中的那些锁
  • 原文地址:https://www.cnblogs.com/heyujun/p/10101269.html
Copyright © 2011-2022 走看看