[HDU 4776 Ants] Trie异或+预处理

题目

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;
}

你可能感兴趣的:([HDU 4776 Ants] Trie异或+预处理)