HDU-6191 Query on A Tree(字典树+启发式合并)

Query on A Tree

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)
Total Submission(s): 1732    Accepted Submission(s): 566

Problem Description

Monkey A lives on a tree, he always plays on this tree.

One day, monkey A learned about one of the bit-operations, xor. He was keen of this interesting operation and wanted to practise it at once.

Monkey A gave a value to each node on the tree. And he was curious about a problem.

The problem is how large the xor result of number x and one node value of label y can be, when giving you a non-negative integer x and a node label u indicates that node y is in the subtree whose root is u(y can be equal to u).

Can you help him?

Input

There are no more than 6 test cases.

For each test case there are two positive integers n and q, indicate that the tree has n nodes and you need to answer q queries.

Then two lines follow.

The first line contains n non-negative integers V1,V2,⋯,Vn, indicating the value of node i.

The second line contains n-1 non-negative integers F1,F2,⋯Fn−1, Fi means the father of node i+1.

And then q lines follow.

In the i-th line, there are two integers u and x, indicating that the node you pick should be in the subtree of u, and x has been described in the problem.

2≤n,q≤105

0≤Vi≤109

1≤Fi≤n, the root of the tree is node 1.

1≤u≤n,0≤x≤109

Output

For each query, just print an integer in a line indicating the largest result.

Sample Input

2 2 1 2 1 1 3 2 1

Sample Output

2 3

Source

2017ACM/ICPC广西邀请赛-重现赛(感谢广西大学)

题意:一棵树上,每次输入u x,询问以u为根节点的子树上的某个点与x异或最大可以是多少

题解:树上启发式合并

对于每个节点都搞一个字典树,进行启发式合并即可。

一开始被卡内存了= =,弄了个pool记录废物节点,重复利用下内存就过了。。

时间复杂度O(nlog^2 n)

#include <bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
#define rep(i,a,b) for(int i=(a);i<(b);++i)
#define per(i,a,b) for(int i=(a)-1;i>=(b);--i)
#define fuck(x) cout<<'['<<#x<<' '<<(x)<<']'<<endl
#define clr(x,y) memset(x,y,sizeof(x))
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> VI;
typedef pair<int, int> PII;

const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int mod = 1e9 + 7;

const int MX = 1e5 + 7;
VI E[MX];
int val[MX], ans[MX];
vector<PII> ver[MX];

const int MXM = MX * 31;
int nxt[MXM][2], rear;
int pool[MXM], cnt, tot;

void init(int n) {
    rep(i, 1, n + 1) {
        E[i].clear();
        ver[i].clear();
    }
    cnt = rear = tot = 0;
}

struct Trie {
    int root;
    int new_node() {
        if(cnt) rear = pool[cnt--];
        else rear = ++tot;
        memset(nxt[rear], 0, sizeof(nxt[rear]));
        return rear;
    }
    void init() {
        root = new_node();
    }
    void dfs(int u) {
        if(nxt[u][0]) dfs(nxt[u][0]);
        if(nxt[u][1]) dfs(nxt[u][1]);
        pool[++cnt] = u;
    }
    void del() {
        dfs(root);
    }
    void insert(int x) {
        int now = root, tmp;
        per(i, 31, 0) {
            tmp = x >> i & 1;
            if (!nxt[now][tmp]) nxt[now][tmp] = new_node();
            now = nxt[now][tmp];
        }
    }
    int query(int x) {
        int now = root, tmp, ret = 0;
        per(i, 31, 0) {
            tmp = x >> i & 1;
            if(!nxt[now][tmp ^ 1]) now = nxt[now][tmp];
            else {
                now = nxt[now][tmp ^ 1];
                ret |= 1 << i;
            }
        }
        return ret;
    }
} t[MX];

VI son[MX];
void merge(VI& v1, VI& v2, Trie& t1, Trie& t2) {
    if(v2.size() > v1.size()) swap(v1, v2), swap(t1, t2);
    t2.del();
    rep(i, 0, v2.size()) v1.pb(v2[i]);
    rep(i, 0, v2.size()) t1.insert(v2[i]);
    v2.clear();
}
void dfs(int u) {
    son[u].clear(), son[u].pb(val[u]);
    t[u].init(), t[u].insert(val[u]);
    rep(i, 0, E[u].size()) {
        int v = E[u][i];
        dfs(v);
        merge(son[u], son[v], t[u], t[v]);
    }
    rep(i, 0, ver[u].size()) ans[ver[u][i].y] = t[u].query(ver[u][i].x);
}

int main() {
#ifdef local
    freopen("in.txt", "r", stdin);
#endif // local
    int n, q, u, v, x;
    while(cin >> n >> q) {
        init(n);
        rep(i, 1, n + 1) scanf("%d", &val[i]);
        rep(i, 2, n + 1) {
            scanf("%d", &v);
            E[v].pb(i);
        }
        rep(i, 1, q + 1) {
            scanf("%d%d", &u, &x);
            ver[u].pb(PII(x, i));
        }
        dfs(1);
        rep(i, 1, q + 1) printf("%d\n", ans[i]);
    }

    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值