HDU 6191 Query on A Tree ( 2017广西邀请赛 && 可持久化Trie )

题目链接

题意 : 给你一棵树、树上的每个点都有点权、之后有若干次问询、每次问询给出一个节点编号以及一个整数 X 、问你以给出节点为根的子树中哪个节点和 X 异或最大、输出这个值

 

分析 :

看到这种树上异或最值的问题

可以考虑使用 Trie 来解决

首先涉及到子树

我们可以利用 DFS 序来构造出每个根的子树

DFS 序有很好的性质、其子树的所有节点必定是序列中连续的一段

那么我们就可以对这个 DFS 序列建立可持久化 Trie

然后通过类似前缀和减法的方式得到问询节点子树表示的区间中

所有数组成的 Trie 、然后通过贪心的方法来得到最大异或值

 

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
const int maxNode = (maxn<<5);
int root[maxn];
int sz[maxNode];
int ch[maxNode][2];
int totNode = 0;

int newNode()
{
    totNode++;
    memset(ch[totNode], 0, sizeof(ch[totNode]));
    sz[totNode] = 0;
    return totNode;
}

inline void Insert(int F, int C, int val)
{
    F = root[F], C = root[C];
    for(int i=30; i>=0; i--){
        int bit = (val>>i) & 1;
        if(!ch[C][bit]){
            ch[C][bit] = newNode();
            ch[C][!bit] = ch[F][!bit];
            sz[ ch[C][bit] ] = sz[ ch[F][bit] ];
        }
        C = ch[C][bit], F = ch[F][bit];
        sz[C]++;
    }
}

int Query(int x, int y, int val)
{
    int ret = 0;
    for(int i=30; i>=0; i--){
        int c = (val>>i) & 1;
        if(sz[ch[y][!c]] - sz[ch[x][!c]] > 0)
            ret += (1<<i),
            y = ch[y][!c],
            x = ch[x][!c];
        else x = ch[x][c], y = ch[y][c];
    }
    return ret;
}

struct EDGE{ int v, w, nxt; }Edge[maxn];
int Head[maxn], EdgeCnt = 0;
int weight[maxn];

inline void Edge_init(int n)
{
    memset(sz, 0, sizeof(sz));
    memset(ch, 0, sizeof(ch));
    memset(Head, -1, sizeof(Head));
    EdgeCnt = 0;
}

inline void AddEdge(int From, int To, int Weight)
{
    Edge[EdgeCnt].v = To;
    Edge[EdgeCnt].w = Weight;
    Edge[EdgeCnt].nxt = Head[From];
    Head[From] = EdgeCnt++;
}

int squ[maxn], squLen = 1;
int st[maxn], en[maxn];
void DFS(int v)
{
    st[v] = squLen;
    squ[squLen++] = v;
    for(int i=Head[v]; i!=-1; i=Edge[i].nxt){
        int Eiv = Edge[i].v;
        DFS(Eiv);
    }
    en[v] = squLen-1;
}


int main(void)
{

    int n, q;
    while(~scanf("%d %d", &n, &q)){

        squLen = 1;
        totNode = 0;
        Edge_init(n);

        for(int i=1; i<=n; i++) scanf("%d", &weight[i]);
        for(int i=1; i<=n-1; i++){
            int Fa; scanf("%d", &Fa);
            AddEdge(Fa, i+1, weight[i]);
        }

        DFS(1);

        root[0] = ch[0][0] = ch[0][1] = 0;
        for(int i=1; i<squLen; i++) root[i] = newNode();
        for(int i=1; i<squLen; i++)
            Insert(i-1, i, weight[squ[i]]);

        while(q--){
            int v, x;
            scanf("%d %d", &v, &x);
            printf("%d\n", Query(st[v]-1, en[v], x));
        }
    }
    return 0;
}
View Code

 

posted @ 2018-08-29 22:06  qwerity  阅读(146)  评论(0编辑  收藏  举报