题意:给你一棵树,树上每个点有一个值,q个询问,每个询问求u到v的路径上,下标为0,k,2*k···的点的异或和为多少。
题解:分块的思想,我们对于每个点,记录他往上跳len步到root的异或和,对于询问假如k大于len,我们一步一步跳,假如小于len,我们直接用记录的数据计算出答案。
这题细节很多= =。
AC代码:
#include<stdio.h>
#include<vector>
#include<math.h>
#include<string.h>
#define N 50005
using namespace std;
vector<int>vt[N];
int deep[N],p[N][20],n,m,len;
int a[N],sum[N][255];
void dfs(int u,int fa)
{
int now=u,step=0;
deep[u]=deep[fa]+1;
p[u][0]=fa;
while(step<255)
{
sum[u][step]=a[u]^sum[now][step];
now=p[now][0];
step++;
}
for(int i=0;i<vt[u].size();i++) {
int to=vt[u][i];
if(to==fa)continue;
dfs(to,u);
}
}
void init() {
int i,j; //p[i][j]表示i结点的第2^j祖先
for(j=1;(1<<j)<=n;j++)
for(i=1;i<=n;i++)
if(p[i][j-1]!=-1) p[i][j]=p[p[i][j-1]][j-1];
//i的第2^j祖先就是i的第2^(j-1)祖先的第2^(j-1)祖先
}
int lca(int a,int b) {//最近公共祖先
int i,j;
if(deep[a]<deep[b])swap(a,b);
for(i=0;(1<<i)<=deep[a];i++); i--;
for(j=i;j>=0;j--) //使a,b两点的深度相同
if(deep[a]-(1<<j)>=deep[b]) a=p[a][j];
if(a==b)return a;
for(j=i;j>=0;j--) {
if(p[a][j]!=-1&&p[a][j]!=p[b][j]) {
a=p[a][j]; b=p[b][j];
}
}
return p[a][0];
}
int getk(int now,int x)
{
for(int i=19;i>=0;--i)
if(x>=(1<<i))
{
now=p[now][i];
x-=(1<<i);
if(now==0)break;
}
return now;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(sum,0,sizeof(sum));
for(int i=0;i<50005;i++)vt[i].clear();
len=(int)sqrt(n);deep[1]=1;
for(int i=0;i<n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
vt[u].push_back(v);
vt[v].push_back(u);
}
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dfs(1,0);
init();
while(m--)
{
int u,v,k;
scanf("%d%d%d",&u,&v,&k);
int lc=lca(u,v);
int numu=deep[u]-deep[lc];
int numv=deep[v]-deep[lc];
int ans;
if(k<=len)
{
ans=sum[u][k];
int s1=(numu)%k;
numu=k-s1;
int now=lc;
now=getk(now,numu);
ans^=sum[now][k];
int need=numv-numu;
if(need>=0&&v!=lc)
{
need%=k;
v=getk(v,need);
ans^=sum[v][k];
s1=(numv-need)%k;
numv=(k-s1)%k;
now=lc;
now=getk(now,numv);
ans^=sum[now][k];
}
}
else
{
int now=u;ans=0;
while(deep[now]>=deep[lc])
{
ans^=a[now];
now=getk(now,k);
}
int s1=(numu)%k;
numu=k-s1;
int need=numv-numu;
if(need>=0&&v!=lc)
{
now=v;
need%=k;
now=getk(now,need);
while(deep[now]>deep[lc])
{
ans^=a[now];
now=getk(now,k);
}
}
}
printf("%d\n",ans);
}
}
}