hdu 4757 Tree 南京网络赛 1010
可持久化字典树,每个节点存一棵根节点到它的节点构成的字典树,利用父节点的信息来构树。查询的时候通过最近公共祖先,查询的两个点,三个点的共同信息可以得到两点路径除公共祖先外的点构成的字典树的情况,从而得出最优解。
#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int maxn=1e5+9,maxm=2e6;int a[maxn],f[maxn];int n,m;bool visit[maxn];struct{ int from,to,w,fa;}qry[maxn];struct ED{ int head[maxn],lon; struct { int next,to,from,id; }e[maxn<<1]; void clear() { memset(head,-1,sizeof(head)); lon=0; } void add(int from,int to,int id=0) { e[++lon].to=to; e[lon].from=from; e[lon].next=head[from]; e[lon].id=id; head[from]=lon; }}edge[2];struct T{ int lon,root[maxn]; struct { int to[2],son; }node[maxm]; void clear() { root[0]=lon=0; for(int i=0;lon<150000;i++) { node[i].to[0]=++lon; node[i].to[1]=++lon; node[i].son=0; } } void insert(int t,int now) { int r=root[t]; node[++lon]=node[r]; r=root[now]=lon; for(int i=16;i>=0;i--) { int u=(1<<i&a[now])>0; node[++lon]=node[node[r].to[u]]; r=node[r].to[u]=lon; node[r].son++; } }}tr;int find(int x){ if(f[x]!=x) f[x]=find(f[x]); return f[x];}void merge(int a,int b){ f[find(b)]=find(a);}void dfs(int t,int from){ visit[t]=1; for(int k=edge[1].head[t];k!=-1;k=edge[1].e[k].next) { int u=edge[1].e[k].to; int id=edge[1].e[k].id; if(visit[u]) qry[id].fa=find(u); } for(int k=edge[0].head[t];k!=-1;k=edge[0].e[k].next) { int u=edge[0].e[k].to; if(u==from) continue; dfs(u,t); } merge(from,t);}void getlca(){ memset(visit,0,sizeof(visit)); for(int i=1;i<=n;i++) f[i]=i; dfs(1,0);}void built(int t,int from){ for(int k=edge[0].head[t];k!=-1;k=edge[0].e[k].next) { int u=edge[0].e[k].to; if(u==from) continue; tr.insert(t,u); built(u,t); }}inline int get(int r,int u){ return tr.node[tr.node[r].to[u]].son;}int ask(int t){ int ans=0; int s1=qry[t].from,s2=qry[t].to,s3=qry[t].fa,w=qry[t].w; int r1=tr.root[s1],r2=tr.root[s2],r3=tr.root[s3]; for(int i=16;i>=0;i--) { int u=(1<<i&w)>0; u^=1; if(get(r1,u)+(get(r2,u))>get(r3,u)*2) ans+=(1<<i); else u^=1; r1=tr.node[r1].to[u]; r2=tr.node[r2].to[u]; r3=tr.node[r3].to[u]; } ans=max(ans,a[s3]^w); return ans;}void solve(){ for(int i=1;i<=m;i++) { cout<<ask(i)<<endl;; }}int main(){// freopen("in.txt","r",stdin); while(scanf("%d %d",&n,&m)!=EOF) { edge[0].clear(); edge[1].clear(); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1,from,to;i<n;i++) { scanf("%d %d",&from,&to); edge[0].add(from,to); edge[0].add(to,from); } for(int i=1,from,to,w;i<=m;i++) { scanf("%d %d %d",&from,&to,&w); qry[i].from=from; qry[i].to=to; qry[i].w=w; edge[1].add(from,to,i); edge[1].add(to,from,i); } getlca(); tr.clear(); edge[0].add(0,1); built(0,-1); solve(); } return 0;}