HDU - 6191 Query on A Tree

题意:

  给出一个带点权的树。q次询问,每次询问给出u和x,求点u的子树中与x异或的最大值。

题解:

  将询问离线化。

  每颗节点动态建立字典树。每个节点和自己的孩子合并,但是这样会改变子树节点的字典树,所以就在每个节点回溯的时候计算出该节点的答案。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 1e5+5;
int n, q;
int tot, num, f;
int w[N];
int root[N];
int head[N], to[N], nxt[N];
int tre[N*40][2];
int u, x;
vector<int> g[N];
vector<int> id[N];
int ans[N];
void build(int id) {
    scanf("%d", &w[id]);
    root[id] = ++tot;
    int c = tot;
    for(int i = 30; i >= 0; i--) {
        if(w[id]&(1<<i)) tre[c][1] = ++tot;
        else tre[c][0] = ++tot;
        c = tot;
    }
}
void update(int u, int v) {
    if(tre[v][0]>0) {
        if(tre[u][0]==0) tre[u][0] = tre[v][0];
        else update(tre[u][0], tre[v][0]);
    }
    if(tre[v][1]>0) {
        if(tre[u][1]==0) tre[u][1] = tre[v][1];
        else update(tre[u][1], tre[v][1]);
    }
}
int query(int u, int x) {
    int res = 0;
    int c = root[u];
    for(int i = 30; i >= 0; i--) {
        int p = (x>>i)&1;
        if(tre[c][p^1] > 0) res |= (1<<i), c = tre[c][p^1];
        else if(tre[c][p] > 0) c = tre[c][p];
    }
    return res;
}
void dfs(int u) {
    for(int i = head[u]; ~i; i = nxt[i]) {
        dfs(to[i]);
        update(root[u], root[to[i]]);
    }
    int len = g[u].size();
    for(int i = 0; i < len; i++) ans[id[u][i]] = query(u, g[u][i]);
}
int main() {
    while(~scanf("%d%d", &n, &q)) {
        tot = num = 0;
        memset(tre, 0, sizeof(tre));
        memset(head, -1, sizeof(head));
        for(int i = 1; i <= n; i++) {
            g[i].clear();
            id[i].clear();
        }
        for(int i = 1; i <= n; i++) build(i);
        for(int i = 2; i <= n; i++) {
            scanf("%d", &f);
            to[++num] = i; nxt[num] = head[f]; head[f] = num;
        }
        for(int i = 1; i <= q; i++) {
            scanf("%d%d", &u, &x);
            g[u].push_back(x);
            id[u].push_back(i);
        }
        dfs(1);
        for(int i = 1; i <= q; i++) printf("%d\n", ans[i]);
    }
}
View Code

 

posted @ 2018-06-07 21:46  Pneuis  阅读(176)  评论(0编辑  收藏  举报