[BZOJ5293][BJOI2018]求和(倍增)
裸的树上倍增。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 5 using namespace std; 6 7 const int N=300010,mod=998244353; 8 struct E{ int to,nxt; }e[N*2]; 9 int fa[N],a[N],dep[N],f[N][21],sm[N][52],pow[N][52]; 10 int h[N],cnt,n,m,x,y,k; 11 12 void add(int u,int v){ e[++cnt].to=v; e[cnt].nxt=h[u]; h[u]=cnt; } 13 14 void Build(int x){ 15 dep[x]=dep[fa[x]]+1; 16 sm[x][0]=1; pow[x][0]=1; 17 rep(i,1,50){ 18 pow[x][i]=((long long)pow[x][i-1]*(long long)dep[x])%mod; 19 sm[x][i]=(sm[fa[x]][i]+pow[x][i])%mod; 20 } 21 for (int i=h[x]; i; i=e[i].nxt) 22 if (e[i].to!=fa[x]){ 23 fa[e[i].to]=x; 24 f[e[i].to][0]=x; 25 Build(e[i].to); 26 } 27 } 28 29 int LCA(int x,int y){ 30 if (dep[x]<dep[y]) swap(x,y); 31 for (int i=19; i>=0; --i) 32 if (dep[f[x][i]]>=dep[y]) x=f[x][i]; 33 if (x==y) return x; 34 for (int i=19; i>=0; --i) 35 if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; 36 return fa[x]; 37 } 38 39 int main(){ 40 freopen("sum.in","r",stdin); 41 freopen("sum.out","w",stdout); 42 scanf("%d",&n); 43 rep(i,1,n-1) scanf("%d%d",&x,&y),add(x,y),add(y,x); 44 dep[0]=-1; Build(1); 45 rep(i,1,19) rep(j,1,n) f[j][i]=f[f[j][i-1]][i-1]; 46 scanf("%d",&m); 47 rep(i,1,m){ 48 scanf("%d%d%d",&x,&y,&k); int lca=LCA(x,y); 49 printf("%d\n",((sm[x][k]+sm[y][k]-sm[fa[lca]][k]-sm[lca][k])%mod+mod)%mod); 50 } 51 return 0; 52 }