1. 程式人生 > >bzoj3261: 最大異或和 (可持久化trie樹)

bzoj3261: 最大異或和 (可持久化trie樹)

多少 ace 經典 經典的 bzoj3261 個數 math 應該 sum

題目鏈接

題解

看到異或和最大就應該想到01 trie樹

我們記\(S_i\)為前i項的異或和

那麽我們的目的是最大化\(S_n\)^\(x\)^\(S_{j-1}\) \((l <= j <= r)\) (註意是\(j-1\), 所以l和r都要減1)
\(S_n\)^\(x\)已經固定, 那麽我們可以把\(S_j\)放入trie樹搞

那麽怎麽處理區間呢?
類似主席樹
記錄一下\([1-i]\)每個節點被多少個數經過

那麽兩棵trie樹相減,就得到了 \([l-r]\)這段區間的信息

然後就是經典的模型了

Code

#include<bits/stdc++.h>
const int N = 600010, M = 25;
#define LL long long
#define RG register

int ch[N*30][2], sum[N*30], root[N], cnt, tot, ans;

using namespace std;

inline int gi() {
    RG int x = 0; RG char c = getchar(); bool f = 0;
    while (c != '-' && (c < '0' || c > '9')) c = getchar();
    if (c == '-') c = getchar(), f = 1;
    while (c >= '0' && c <= '9') x = x*10+c-'0', c = getchar();
    return f ? -x : x;
}

void insert(int &now, int x, int dep) {
    sum[++cnt] = sum[now]+1;
    ch[cnt][0] = ch[now][0]; ch[cnt][1] = ch[now][1];
    now = cnt;
    if (dep < 0) return ;
    insert(ch[now][(x >> dep) & 1], x, dep-1);
    return ;
}

void query(int rt1, int rt2, int x, int dep) {
    if (dep < 0) return ;
    int k = (x >> dep)&1;
    if (sum[ch[rt2][k^1]]-sum[ch[rt1][k^1]] > 0) {
        ans |= (1 << dep);
        query(ch[rt1][k^1], ch[rt2][k^1], x, dep-1);
    }
    else query(ch[rt1][k], ch[rt2][k], x, dep-1);   
    return ;
}

int main() {
    //freopen(".in", "r", stdin);
    //freopen(".out", "w", stdout);
    int n = gi(), m = gi();
    for (int i = 1; i <= n; i++) {
        int x = gi();
        tot ^= x; root[i] = root[i-1];
        insert(root[i], tot, M-1);
    }
    for (int i = 1; i <= m; i++) {
        char c = getchar();
        while (c != 'A' && c != 'Q') c = getchar();
        if (c == 'A') {
            int x = gi();
            tot ^= x;
            root[n+1] = root[n];
            insert(root[++n], tot, M-1);
        }
        else {
            int l = gi()-1, r = gi()-1, x = gi();
            ans = 0;
            query(root[l-1], root[r], tot^x, M-1);
            if (!l) ans = max(ans, tot^x);
            printf("%d\n", ans);
        }
    }
    return 0;
}

bzoj3261: 最大異或和 (可持久化trie樹)