hdu6191(树上启发式合并)

hdu6191

题意

给你一棵带点权的树,每次查询 \(u\)\(x\) ,求以 \(u\) 为根结点的子树上的结点与 \(x\) 异或后最大的结果。

分析

看到子树,直接上树上启发式合并,看到异或,上 \(Trie\)
这道题就是两个经典的题目结合了一波。

树上启发式合并处理这种需要查询整个子树的题目尤其有用,可以复用大量的信息。
离线查询后,到要查询的结点直接在 \(Trie\) \(01\) 树上跑一下即可。

先去理解一波 树上启发式合并(\(dsu \ on \ tree\)),就会发现这真是一道模板题

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 100;
const int MX = 30;
struct Ex {
    int id, x;
};
struct Trie {
    int val[MAXN * 30], nxt[MAXN * 30][2], L, root;
    int newnode() {
        memset(nxt[L], -1, sizeof nxt[L]);
        return L++;
    }
    void init() {
        L = 0;
        root = newnode();
    }
    void update(int x, int key) {
        int now = root;
        for(int i = MX; i >= 0; i--) {
            int o = (x >> i) & 1;
            if(nxt[now][o] == -1) nxt[now][o] = newnode();
            now = nxt[now][o];
            val[now] += key;
        }
    }
    int query(int x) {
        int res = 0;
        int now = root;
        for(int i = MX; i >= 0; i--) {
            int o = (x >> i) & 1;
            if(val[nxt[now][!o]]) {
                now = nxt[now][!o];
                res |= (1 << i);
            } else {
                now = nxt[now][o];
            }
        }
        return res;
    }
}trie;
vector<Ex> ex[MAXN];
int fa[MAXN], son[MAXN], dep[MAXN], siz[MAXN];
int col[MAXN];
int cnt, head[MAXN];
struct Edge {
    int to, next;
}e[MAXN << 1];
void addedge(int u, int v) {
    e[cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt++;
}
void dfs(int u) {
    siz[u] = 1; son[u] = 0;
    for(int i = head[u]; ~i; i = e[i].next) {
        if(e[i].to != fa[u]) {
            fa[e[i].to] = u;
            dep[e[i].to] = dep[u] + 1;
            dfs(e[i].to);
            if(siz[e[i].to] > siz[son[u]]) son[u] = e[i].to;
            siz[u] += siz[e[i].to];
        }
    }
}
int n, q;
int vis[MAXN];
int ans[MAXN];
void update(int u, int key) {
    trie.update(col[u], key);
    for(int i = head[u]; ~i; i = e[i].next) {
        if(e[i].to != fa[u] && !vis[e[i].to]) update(e[i].to, key);
    }
}
void dfs1(int u, int flg) {
    for(int i = head[u]; ~i; i = e[i].next) {
        if(e[i].to != fa[u] && e[i].to != son[u]) dfs1(e[i].to, 1);
    }
    if(son[u]) {
        dfs1(son[u], 0);
        vis[son[u]] = 1;
    }
    update(u, 1);
    for(int i = 0; i < ex[u].size(); i++) {
        ans[ex[u][i].id] = trie.query(ex[u][i].x);
    }
    if(son[u]) vis[son[u]] = 0;
    if(flg) {
        update(u, -1);
    }
}

int main() {
    while(~scanf("%d%d", &n, &q)) {
        for(int i = 1; i <= n; i++) {
            ex[i].clear();
            fa[i] = son[i] = dep[i] = siz[i] = 0;
        }
        memset(vis, 0, sizeof vis);
        memset(ans, 0, sizeof ans);
        trie.init();
        cnt = 0;
        memset(head, -1, sizeof head);
        for(int i = 1; i <= n; i++) {
            scanf("%d", &col[i]);
        }
        for(int i = 2; i <= n; i++) {
            int u;
            scanf("%d", &u);
            addedge(u, i);
            addedge(i, u);
        }
        for(int i = 0; i < q; i++) {
            int u, x;
            scanf("%d%d", &u, &x);
            ex[u].push_back(Ex{i, x});
        }
        dfs(1);
        dfs1(1, -1);
        for(int i = 0; i < q; i++) {
            printf("%d\n", ans[i]);
        }
    }
    return 0;
}
posted @ 2017-08-31 18:14  ftae  阅读(192)  评论(0编辑  收藏  举报