题目:洛谷P4427。
题目大意:
一棵树,根节点1深度为0。设点i的深度为(d_i)。
现在有m个询问,每个询问选择2个点x,y,并给出k。问x到y路径上(sum d_i ^k)。
解题思路:
由于k最大50,我们预处理出k等于1~50的所有节点的树上差分,然后LCA即可。
C++ Code:
#include<bits/stdc++.h> #define N 300005 #define md 998244353 #define LoveLive long long int n,head[N],cnt=0,k; LoveLive dep[51][N],s[51][N]; int p[N][22]; inline int readint(){ int c=getchar(),d=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } struct edge{ int to,nxt; }e[N<<1]; void dfs(int now){ for(int i=head[now];i;i=e[i].nxt) if(!~dep[1][e[i].to]){ p[e[i].to][0]=now; dep[1][e[i].to]=dep[1][now]+1; dfs(e[i].to); } } void ssum(int now){ for(int i=head[now];i;i=e[i].nxt) if(dep[1][e[i].to]==dep[1][now]+1){ s[k][e[i].to]=(s[k][now]+dep[k][e[i].to])%md; ssum(e[i].to); } } int lca(int x,int y){ if(dep[1][x]<dep[1][y])x^=y^=x^=y; for(int i=21;i>=0;--i) if(dep[1][p[x][i]]>=dep[1][y])x=p[x][i]; if(x==y)return x; for(int i=21;i>=0;--i) if(p[x][i]&&p[x][i]!=p[y][i])x=p[x][i],y=p[y][i]; return p[x][0]; } int main(){ n=readint(); memset(head,0,sizeof head); for(int i=1;i<n;++i){ int u=readint(),v=readint(); e[++cnt]=(edge){v,head[u]}; head[u]=cnt; e[++cnt]=(edge){u,head[v]}; head[v]=cnt; } memset(dep,-1,sizeof dep); dep[1][1]=0; dfs(1); for(int i=2;i<=50;++i){ for(int j=1;j<=n;++j) dep[i][j]=dep[i-1][j]*dep[1][j]%md; } memset(s,0,sizeof s); for(k=1;k<=50;++k)ssum(1); for(int j=1;j<21;++j) for(int i=1;i<=n;++i){ p[i][j]=p[p[i][j-1]][j-1]; } for(int m=readint();m--;){ int x=readint(),y=readint();k=readint(); int l=lca(x,y); LoveLive ans=(s[k][x]+s[k][y]-s[k][l]-s[k][p[l][0]]+1LL*md*4)%md; printf("%lld ",ans); } return 0; }