可持久化Trie,大概和树上主席树一个做法
(竟然轻易地就1A了)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<cmath> using namespace std; #define rep(i,l,r) for(int i=l;i<=r;i++) #define per(i,r,l) for(int i=r;i>=l;i--) #define mmt(a,v) memset(a,v,sizeof(a)) #define tra(i,u) for(int i=head[u];i;i=e[i].next) const int N=100000+5; int ch[N*20][2],sum[N*20]; int sz; void insert(int &x,int y,int z){ sz++;ch[sz][0]=ch[x][0];ch[sz][1]=ch[x][1];sum[sz]=sum[x];x=sz; sum[x]++; if(!z)return; int k=(y>>z-1)&1; insert(ch[x][k],y,z-1); } int query(int u,int v,int w,int f,int z,int i){ if(!i)return 0; int k=((z>>i-1)&1)^1; if(sum[ch[u][k]]+sum[ch[v][k]]-sum[ch[w][k]]-sum[ch[f][k]]) return (1<<i-1)+query(ch[u][k],ch[v][k],ch[w][k],ch[f][k],z,i-1); else return query(ch[u][k^1],ch[v][k^1],ch[w][k^1],ch[f][k^1],z,i-1); } struct Edge{int to,next;}e[N<<1]; int head[N],cnt; void ins(int u,int v){e[++cnt]=(Edge){v,head[u]};head[u]=cnt;} void insert(int u,int v){ins(u,v);ins(v,u);} int fa[N],dep[N],son[N],top[N],siz[N]; int root[N],a[N]; void dfs(int u){ son[u]=0;siz[u]=1; root[u]=root[fa[u]]; insert(root[u],a[u],16); tra(i,u){ int v=e[i].to;if(v==fa[u])continue; fa[v]=u;dep[v]=dep[u]+1;dfs(v); siz[u]+=siz[v];if(siz[v]>siz[son[u]])son[u]=v; } } void dfs(int u,int tp){ top[u]=tp; if(son[u])dfs(son[u],tp); tra(i,u){ int v=e[i].to; if(v!=fa[u]&&v!=son[u]) dfs(v,v); } } int lca(int u,int v){ while(top[u]!=top[v]) if(dep[top[u]]>dep[top[v]])u=fa[top[u]]; else v=fa[top[v]]; return dep[u]<dep[v]?u:v; } int query(int u,int v,int z){ int w=lca(u,v); return query(root[u],root[v],root[w],root[fa[w]],z,16); } int main(){ //freopen("a.in","r",stdin); int n,m; while(~scanf("%d%d",&n,&m)){ mmt(head,0);cnt=0; rep(i,1,n)scanf("%d",&a[i]); rep(i,2,n){int u,v;scanf("%d%d",&u,&v);insert(u,v);} root[0]=sz=0;ch[0][0]=ch[0][1]=sum[0]=0; dfs(1);dfs(1,1); while(m--){ int u,v,z;scanf("%d%d%d",&u,&v,&z); printf("%d\n",query(u,v,z)); } } return 0; }