题目
http://acm.hdu.edu.cn/showproblem.php?pid=4776
分析
Trie异或+预处理
有点用到NOI 2011 Piano的思想的意思,因为k不大,所以把k大值一个一个都找出来
首先做一遍bfs把每个点到根的距离dist[]求出来,那么两个点的距离就是dist的异或值
然后把n个点的dist都插进trie里,然后把每个点的最大值都找出来,丢进一个堆里,然后每次取出最大的,把对应的点的下一个最大值插进堆里
找每个点的k大值可以通过在trie上记录size解决
练习赛时ans数组开小了wa了好几次
代码
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <vector> #include <queue> using namespace std; typedef long long ll; const int MAX_N = 100005; const int MAX_E = 200005; const int MAX_K = 200005; const int MAX_M = 6400005; struct Node { int size; Node *ch[2]; Node() { size = 0; memset(ch, 0, sizeof(ch)); } }; struct Edge { int dest; ll cost; Edge *next; Edge() {} Edge(int _dest, ll _cost, Edge *_next) : dest(_dest), cost(_cost), next(_next) {} }; Edge EdgePool[MAX_E]; Edge *EP; Edge *e[MAX_N]; priority_queue< pair<ll, int> > heap; Node NodePool[MAX_M]; Node *NP; Node *root; int n; ll dist[MAX_N]; ll ans[MAX_K]; int cur[MAX_N]; int Q[MAX_N]; bool vis[MAX_N]; inline void addedge(int a, int b, ll c) { e[a] = new(EP++)Edge(b, c, e[a]); e[b] = new(EP++)Edge(a, c, e[b]); } void insert(ll val) { Node *t = root; for (int i = 63; i >= 0; i--) { t->size++; int c = (int)((val >> i) & 1); if (!t->ch[c]) { t->ch[c] = new(NP++)Node(); } t = t->ch[c]; } t->size++; } ll query(ll val, int k) { Node *t = root; ll ret = 0; for (int i = 63; i >= 0; i--) { ret <<= 1; int c = (int)((val >> i) & 1); int _c = c ^ 1; if (t->ch[_c] && t->ch[_c]->size >= k) { // printf("0 (%d, %d) %d\n", _c, t->ch[_c]->size, k); t = t->ch[_c]; ret |= _c; } else { // printf("1 (%d, %d) %d\n", c, (t->ch[_c] ? t->ch[_c]->size : 0), k); k -= t->ch[_c] ? t->ch[_c]->size : 0; t = t->ch[c]; ret |= c; } } // printf("\n"); ret ^= val; return ret; } int main() { // freopen("in.txt", "r", stdin); while (scanf("%d", &n), n) { EP = EdgePool; memset(e, 0, sizeof(e)); NP = NodePool; root = new(NP++)Node(); memset(dist, 0, sizeof(dist)); memset(vis, 0, sizeof(vis)); while (!heap.empty()) { heap.pop(); } for (int i = 1; i < n; i++) { int a, b; ll c; scanf("%d %d %I64d", &a, &b, &c); addedge(a, b, c); } int tail = 0; Q[++tail] = 1; for (int head = 1; head <= tail; head++) { int i = Q[head]; vis[i] = true; for (Edge *j = e[i]; j; j = j->next) { if (!vis[j->dest]) { dist[j->dest] = dist[i] ^ j->cost; Q[++tail] = j->dest; } } } for (int i = 1; i <= n; i++) { // printf("%I64d ", dist[i]); insert(dist[i]); } // printf("\n"); for (int i = 1; i <= n; i++) { cur[i] = 1; ll t = query(dist[i], cur[i]); // printf("TEST : %I64d\n", t); heap.push(make_pair(t, i)); } memset(ans, 0xff, sizeof(ans)); for (int i = 1; i <= 200000 && i <= (ll)n * (n - 1); i++) { pair<ll, int> t = heap.top(); heap.pop(); ans[i] = t.first; cur[t.second]++; if (cur[t.second] < n) { ll res = query(dist[t.second], cur[t.second]); // printf("%d, %I64d, Rank %d: %I64d\n", t.second, dist[t.second], cur[t.second], res); heap.push(make_pair(res, t.second)); } } int q; scanf("%d", &q); for (int i = 1; i <= q; i++) { int k; scanf("%d", &k); printf("%I64d\n", ans[k]); } } return 0; }