[十二省聯考2019]異或粽子 01trie
阿新 • • 發佈:2019-04-13
wro std 主席樹 每次 鏈接 http -i ons getchar
還有一種是把k*2,這樣消去了大小限制,直接建立一顆01trie,在上面跑k大,最後除以2
對角線上是有重復的,但是你一定選不到呀,xor起來為0
[十二省聯考2019]異或粽子 01trie
鏈接
luogu
思路
首先求前k大的(xo[i]^xo[j])(i<j)。
考場上只想到01trie,不怎麽會寫可持久,就寫了n個01trie,和直接sort一樣、、
咳咳,官方題解是。
一個堆維護i為終點,可以取得位置為\([L,R]\)的最大值為val。
每次選最大的,然後將這個點分裂成兩個:
i為終點,可以取得位置為\([L,x-1]\)的最大值為\(val_1\)。
i為終點,可以取得位置為\([x+1,R]\)的最大值為\(val_2\)。
具體咋維護,可持久01trie(他應該就是說的主席樹,忘記啦)。
其實可以直接是直接記錄當前應該取第幾大,建立可持久化01trie
對角線上是有重復的,但是你一定選不到呀,xor起來為0
錯誤
1.一個hello wrold居然跑10s,垃圾病毒防護天天掃我exe。
2.我居然不知道trie可以求第k大xor值,菜的一批、、、、
3.這細節,好麻煩,不知道為啥不能從0開始標號,不知道for從0開始
代碼
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 5e5 + 6; ll read() { ll x = 0, f = 1; char s = getchar(); for (; s > '9' || s < '0'; s = getchar()) if (s == '-') f = -1; for (; s >= '0' && s <= '9'; s = getchar()) x = x * 10 + s - '0'; return x * f; } int n, k, cnt=1, num[N]; ll a[N]; struct node { int ch[2], siz; } e[N * 35]; priority_queue<pair<ll, int> > q; void insert(ll x) { int p = 1; for (int i = 31; i >= 0; --i) { bool T_T = x & (1LL << i); e[p].siz++; if (!e[p].ch[T_T]) e[p].ch[T_T] = ++cnt; p = e[p].ch[T_T]; } e[p].siz++; } ll k_th(ll x, int k) { if (k > n) return 0; ll ans = 0; int p = 1; for (int i = 31; i >= 0; --i) { bool T_T = x & (1LL << i); if (e[e[p].ch[T_T ^ 1]].siz >= k) ans = ans | (1LL << i), p = e[p].ch[T_T ^ 1]; else k -= e[e[p].ch[T_T ^ 1]].siz, p = e[p].ch[T_T]; } return ans; } int main() { n = read(), k = read() * 2; insert(0); for (int i = 1; i <= n; ++i) a[i] = a[i - 1] ^ read(), insert(a[i]); for (int i = 0; i <= n; ++i) q.push(make_pair(k_th(a[i],num[i]=1),i)); ll ans = 0; while (k--) { pair<ll, int> u = q.top(); q.pop(); ans += u.first; u.first=k_th(a[u.second],++num[u.second]); if(num[u.second]<n) q.push(u); } cout << ans / 2 << "\n"; return 0; }
[十二省聯考2019]異或粽子 01trie