题意:给一棵树,每个点有权值。q次询问a,b,k,问你从a点到b点,每次跳距离k,权值的异或和?
预处理每个点往其根节点的路径上隔1~sqrt(n)的距离的异或和,然后把询问拆成a->lca(a,b),lca(a,b)->b,讨论一下即可,细节比较多。
队友的代码:
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int q,a[50004],fa[50004][18],s[50004][230],nxt[100005],to[100005],head[100005],en,sq,n,vis[50004],deep[50004]; void add(int u,int v) { nxt[++en]=head[u]; head[u]=en; to[en]=v; } int get(int now,int x) { for(int i=17;i>=0;--i) if(x>=(1<<i)) { now=fa[now][i]; x-=(1<<i); } return now; } void dfs(int now) { vis[now]=1; for(int i=1;i<=17;++i) { fa[now][i]=fa[fa[now][i-1]][i-1]; } for(int i=1;i<=sq;++i) { s[now][i]=s[get(now,i)][i]^a[now]; } for(int i=head[now];i;i=nxt[i]) if(!vis[to[i]]) { fa[to[i]][0]=now; deep[to[i]]=deep[now]+1; dfs(to[i]); } } int lca(int u,int v) { for(int i=17;i>=0;--i) if(deep[fa[u][i]]>=deep[v]) u=fa[u][i]; for(int i=17;i>=0;--i) if(deep[fa[v][i]]>=deep[u]) v=fa[v][i]; if(u==v)return u; for(int i=17;i>=0;--i) if(fa[u][i]!=fa[v][i]) { u=fa[u][i]; v=fa[v][i]; } return fa[u][0]; } int main() { while(scanf("%d%d",&n,&q)!=EOF) { int u,v,k; for(int i=1;i<n;++i) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } sq=sqrt(n); for(int i=1;i<=n;++i) scanf("%d",&a[i]); deep[1]=1; dfs(1); for(int i=1;i<=q;++i) { scanf("%d%d%d",&u,&v,&k); if(k<=sq) { int nowans=0; int l=lca(u,v); int l1=(deep[u]-deep[l])%k; int ll=get(l,k-l1); nowans^=s[u][k]; nowans^=s[ll][k]; int l2=(deep[v]-deep[l]); if(l2>=k-l1&&v!=l) { l2-=(k-l1); v=get(v,l2%k); l1=(deep[v]-deep[l])%k; if(l1==0) ll=l; else ll=get(l,k-l1); nowans^=s[v][k]; nowans^=s[ll][k]; } printf("%d ",nowans); } else { int nowans=0; int l=lca(u,v); int l1=(deep[u]-deep[l])%k; int ll=get(l,k-l1); int now=u; while(deep[now]>=deep[l]) { nowans^=a[now]; now=get(now,k); } int l2=(deep[v]-deep[l]); if(l2>=k-l1&&v!=l) { l2-=(k-l1); v=get(v,l2%k); now=v; while(deep[now]>deep[l]) { nowans^=a[now]; now=get(now,k); } } printf("%d ",nowans); } } en=0; for(int i=1;i<=n;++i) { head[i]=0; for(int j=1;j<=sq;++j) s[i][j]=0; a[i]=0; vis[i]=0; deep[i]=0; for(int j=0;j<=17;++j) fa[i][j]=0; } } return 0; }