hdu4757 Tree

来源:互联网 发布:linux退出vi编辑 编辑:程序博客网 时间:2024/06/11 11:33

可持久化Trie,比赛的时候一直在想不到怎么样才可以做减法,赛后才想清楚。

首先异或最大就是在字典树上找它的按位取反,首先满足高位。

对每个节点维护一个Trie,维护的是它到根所有路过的节点的权值,维护Trie的时候同时维护一下子树的叶子节点个数。

对于每一个询问先倍增求出LCA,再由三个节点的权值来计算某子树的叶子节点个数,判断能不能走到某个儿子,如果某棵子树没有叶子节点就意味着不能走。

说的比较抽象,看代码比较好懂吧。。大概

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <cstdlib>#include <cmath>#include <cctype>#include <queue>#include <stack>#include <map>#include <set>#include <list>#define pb push_back#define mp make_pair#define fi first#define se second//#pragma comment(linker, "/STACK:16777216")using namespace std;typedef long long LL;typedef unsigned long long ULL;#define N 100010#define M 2000000int u[M][2] , v[M] , cnt;int n , m , a[N] , L[N] , f[17][N] , pre[N] , mcnt;struct edge{    int x , next;}e[N << 1];int str[20];int root[N];int newnode(){    memset(u[cnt] , 0 , sizeof(u[cnt]));    v[cnt] = 0;    return cnt ++;}void insert(int x , int y , int val){    x = root[x] , y = root[y];    for (int i = 0 ; i < 16 ; ++ i)    {        int c = val >> (16 - i - 1) & 1;        if (!u[x][c])          u[x][c] = newnode() , u[x][!c] = u[y][!c] , v[u[x][c]] = v[u[y][c]];        x = u[x][c] , y = u[y][c];        ++ v[x];    }}int query(int x , int y , int z , int val){    int ans = 0 , res = a[z] ^ val;    x = root[x] , y = root[y] , z = root[z];    for (int i = 0 ; i < 16 ; ++ i)    {        int c = !(val >> (16 - i - 1) & 1);        if (v[u[x][c]] + v[u[y][c]] - v[u[z][c]] - v[u[z][c]] > 0)            ans |= 1 << (16 - i - 1);        else            c = !c;        x = u[x][c] , y = u[y][c] , z = u[z][c];    }    return max(ans , res);}void dfs(int x , int fa){    f[0][x] = fa , L[x] = L[fa] + 1 ;    root[x] = newnode();    insert(x , fa , a[x]);    for (int i = pre[x] ; ~i ; i = e[i].next)        if (e[i].x != fa)            dfs(e[i].x , x);}int LCA(int x , int y){    if (L[x] > L[y]) swap(x , y);    for (int i = 16 ; i >= 0 ; -- i)        if (L[y] - L[x] >= 1 << i)            y = f[i][y];    if (x == y) return y;    for (int i = 16 ; i >= 0 ; -- i)        if (f[i][x] && f[i][x] != f[i][y])            x = f[i][x] , y = f[i][y];    return f[0][x];}void work(){    int  i , j , x , y , z , w;    memset(pre , -1 , sizeof(pre));    mcnt = 0 , cnt = 1;    for (i = 1 ; i <= n ; ++ i)        scanf("%d",&a[i]);    for (i = 1 ; i < n ; ++ i)    {        scanf("%d%d",&x,&y);        e[mcnt].x = y , e[mcnt].next = pre[x] , pre[x] = mcnt ++;        e[mcnt].x = x , e[mcnt].next = pre[y] , pre[y] = mcnt ++;    }    memset(f , 0 , sizeof(f));    dfs(1 , 0);    for (j = 1 ; 1 << j < n ; ++ j)        for (i = 1 ; i <= n ; ++ i)            f[j][i] = f[j - 1][f[j - 1][i]];    while (m --)    {        scanf("%d%d%d",&x,&y,&w);        z = LCA(x , y);        printf("%d\n" , query(x , y , z , w));    }}int main(){    freopen("~input.txt" , "r" , stdin);    while (~scanf("%d%d",&n,&m))        work();    return 0;}


原创粉丝点击