可持久化字典树

Posted cjlhy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可持久化字典树相关的知识,希望对你有一定的参考价值。

#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ull unsigned long long

using namespace std;

const int N = 5e4 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
const double PI = acos(-1);

int n, q, a[N];
char op[10];

namespace Trie {
    int to[32][2], Rt[N], tot;
    int ch[N * 32][2], cnt[N * 32];
    void init() {
        tot = 0;
        for(int i = 0; i <= 30; i++)
            to[i][0] = 0, to[i][1] = 1;
    }
    inline void cpy(int x, int y) {
        ch[x][0] = ch[y][0];
        ch[x][1] = ch[y][1];
        cnt[x] = cnt[y];
    }
    void Insert(int v, int x, int y) {
        cpy(x, y);
        for(int i = 30; i >= 0; i--) {
            if(v >> i & 1 || to[i][0] == to[i][1]) {
                ch[x][1] = ++tot;
                x = ch[x][1]; y = ch[y][1];
                cpy(x, y);
            } else {
                ch[x][0] = ++tot;
                x = ch[x][0]; y = ch[y][0];
                cpy(x, y);
            }
            cnt[x]++;
        }
    }
    void Rebuild(int *a, int n) {
        tot = 0;
        for(int i = 1; i <= n; i++) {
            Rt[i] = ++tot;
            Insert(a[i], Rt[i], Rt[i - 1]);
        }
    }
    int Query(int L, int R, int K) {
        int ans = 0, x = Rt[R], y = Rt[L - 1];
        for(int i = 30; i >= 0; i--) {
            bool op = !(to[i][0] < to[i][1]);
            if(cnt[ch[x][op]] - cnt[ch[y][op]] >= K) {
                ans += to[i][op] << i;
                x = ch[x][op]; y = ch[y][op];
            } else {
                K -= cnt[ch[x][op]] - cnt[ch[y][op]];
                ans += to[i][!op] << i;
                x = ch[x][!op]; y = ch[y][!op];
            }
        }
        return ans;
    }
    void Or(int x) {
        bool need = false;
        for(int i = 0; i <= 30; i++) {
            if(x >> i & 1) {
                if(to[i][0] ^ to[i][1]) need = true;
                to[i][0] = to[i][1] = 1;
            }
        }
        if(need) Rebuild(a, n);
    }
    void And(int x) {
        bool need = false;
        for(int i = 0; i <= 30; i++) {
            if(!(x >> i & 1)) {
                if(to[i][0] ^ to[i][1]) need = true;
                to[i][0] = to[i][1] = 0;
            }
        }
        if(need) Rebuild(a, n);
    }
    void Xor(int x) {
        for(int i = 0; i <= 30; i++)
            if(x >> i & 1) to[i][0] ^= 1, to[i][1] ^= 1;
    }
}

int main() {
//    freopen("text.in", "r", stdin);
    scanf("%d%d", &n, &q);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    Trie::init();
    Trie::Rebuild(a, n);
    while(q--) {
        scanf("%s", op);
        if(op[0] == O) {
            int x; scanf("%d", &x);
            Trie::Or(x);
        } else if(op[0] == A && op[1] == n) {
            int x; scanf("%d", &x);
            Trie::And(x);
        } else if(op[0] == X) {
            int x; scanf("%d", &x);
            Trie::Xor(x);
        } else {
            int L, R, K;
            scanf("%d%d%d", &L, &R, &K);
            printf("%d
", Trie::Query(L, R, K));
        }
    }
    return 0;
}

/*
*/

 

以上是关于可持久化字典树的主要内容,如果未能解决你的问题,请参考以下文章

可持久化字典树 详解

可持久化数据结构板子整理(可持久化 线段树/字典树/可并堆)

可持久化字典树

可持久化字典树

hdu 4757 Tree(可持久化字典树)

bzoj3166: [Heoi2013]Alo 可持久化字典树