HDU 6191 Query on A Tree
阿新 • • 發佈:2018-12-21
題意
\(n\) 個點的有根樹,根為 \(1\) 。每個點有點權,有 \(q\) 個詢問,每次詢問以 \(u\) 為根的子樹的點的點權中異或 \(x\) 所得的最大值是多少。
思路
求出整棵樹的 \(\text{dfs}\) 序,問題就轉化成了序列上,求一個區間中的數字異或 \(x\) 可得的最大值。同樣的方法,只需在原序列上建立可持久化的 \(\text{Trie}\) 樹即可,和區間第 \(K\) 值類似的方法,在 ”主席\(\text{Trie}\) “上找最大解。
程式碼
#include<bits/stdc++.h> #define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i) #define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i) typedef long long LL; using namespace std; const int N=1e5+5; template<const int maxn,const int maxm>struct Linked_list { int head[maxn],to[maxm],nxt[maxm],tot; Linked_list(){clear();} void clear(){memset(head,-1,sizeof(head));tot=0;} void add(int u,int v){to[++tot]=v,nxt[tot]=head[u],head[u]=tot;} #define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i]) }; Linked_list<N,N>G; struct Trie { struct node{int son[2],sum;}; node nd[N*32]; int rt[N],tot; int &operator [](const int x){return rt[x];} void build() { memset(rt,0,sizeof(rt)); nd[tot=0]=(node){0,0,0}; } void create(int &k){nd[++tot]=nd[k],k=tot;} void insert(int &k,int x,int n) { create(k),nd[k].sum++; if(n<0)return; insert(nd[k].son[x>>n&1],x&((1<<n)-1),n-1); } int query(int k,int p,int x,int n) { if(n<0)return 0; if(nd[nd[k].son[~x>>n&1]].sum-nd[nd[p].son[~x>>n&1]].sum>0) return (1<<n)|query(nd[k].son[~x>>n&1],nd[p].son[~x>>n&1],x&((1<<n)-1),n-1); else return query(nd[k].son[x>>n&1],nd[p].son[x>>n&1],x&((1<<n)-1),n-1); } }Tr; int n,q,p[N],L[N],R[N],ori[N],ord; void dfs(int u,int f) { L[u]=++ord,ori[ord]=u; EOR(i,G,u) { int v=G.to[i]; if(v==f)continue; dfs(v,u); } R[u]=ord; } int main() { while(~scanf("%d%d",&n,&q)) { Tr.build(); G.clear(); FOR(i,1,n)scanf("%d",&p[i]); FOR(v,2,n) { int u; scanf("%d",&u); G.add(u,v); } ord=0; dfs(1,0); FOR(i,1,n)Tr.insert(Tr[i]=Tr[i-1],p[ori[i]],30); while(q--) { int u,x; scanf("%d%d",&u,&x); printf("%d\n",Tr.query(Tr[R[u]],Tr[L[u]-1],x,30)); } } return 0; }