1. 程式人生 > 其它 >P5283 異或粽子(Trie)

P5283 異或粽子(Trie)

目錄

Description

有 n 個數,任選兩個數 \(1<=L<=R<=n\),使得 \(k\)\([L,\; R]\) 的區間異或和最大

State

\(1<=n,\; k <=5*10^5\)

\(0<=a[i]<=4294967295\)

Input

3 2
1 2 3

Output

6

Solution

在這裡提供三種解法,程式碼為第三種解法:

​ 1.對於每一個 \(i∈[1,\; n]\) 在區間 \([i,\; n]\) 內尋找一個位置 \(id\) ,使得 \(sum[id]⊕sum[i]\) 最大,將這 \(n\) 個最大值放入堆中,依次取出,再將區間分為 \([i,\; id - 1]\)\([id + 1, \; n]\) 即可,直至挑選 \(k\)

​ 2.由於\(\forall i,\; \exists j,\; sum[i]⊕sum[j]\) 最大,但是由於題目中 \(i<=j\)

所以將 \(k=k*2\),在區間 \([1,\; n]\) 上尋找 \(\forall i\) 的前 \(k\) 大值

​ 3.類似於解法 2, 但是可以將 \(j\) 固定於 \([i, \; n]\) 區間上尋找每一個 \(i\) 的前 \(k\) 大值,這時就需要可持久化 \(Trie\) 了,也因為如此,其需要的空間比上面兩種要更大一點 \((hack)\)

Code

const int N = 5e5 + 5;

    ll n, m, _;
    int i, j, k;
    ll a[N];
    int ch[N * 40][2], sz[N * 40];
    int tot = 0, root[N];

void ins(int &x, int y, ll c)
{
    x = ++ tot; 
    int nx = x, ny = y;
    for(int i = 33; ~ i; i --){
        int id = (c >> i) & 1;
        ch[nx][0] = ch[ny][0];
        ch[nx][1] = ch[ny][1];
        ch[nx][id] = ++ tot;
        nx = ch[nx][id];
        ny = ch[ny][id];
        sz[nx] = sz[ny] + 1;
    }
}

ll query(int rk, ll c, int x, int y)
{
    ll ans = 0;
    for(int i = 33; ~ i; i --){
        int id = (c >> i) & 1;
        int size = sz[ch[y][!id]] - sz[ch[x][!id]];
        if(size >= rk){
            ans |= (1ll << i);
            x = ch[x][!id];
            y = ch[y][!id];
        }
        else{
            rk -= size;
            x = ch[x][id];
            y = ch[y][id];
        }
    }
    return ans;
}

struct Node
{
    int rk, id;
    ll val;
    int l, r;
    Node(){}
    Node(int id, int rk){
        this -> id = id;
        this -> rk = rk;
        l = id, r = n;
        val = query(rk, a[id], root[l], root[r]);
    }
    bool operator<(Node o) const{
        return val < o.val;
    }
};

signed main()
{
    //IOS;
    while(~ sdd(n, k)){
        rep(i, 1, n){
            sll(a[i]);
            a[i] ^= a[i - 1];
        }
        priority_queue<Node> q;
        ins(root[0], root[0], 0ll);
        rep(i, 1, n){
            ins(root[i], root[i - 1], a[i]);
        }
        rep(i, 0, n - 1){
            q.push(Node(i, 1));
        }
        ll ans = 0;
        rep(i, 1, k){
            Node top = q.top();
            q.pop();
            ans += top.val;
            if(top.val != 0) q.push(Node(top.id, top.rk + 1));
        }
        pll(ans);
    }
    return 0;
}