题目链接:https://www.luogu.com.cn/problem/P4427
题意:
给定一颗树,m次询问,每次询问u-v之间每个节点的k次方之和
思路:
树上前缀和:res=ans[u][k]+ans[v][k]-ans[lca(u,v)][k]-ans[fa[lca(u,v)][0]][k]
其中ans[i][j]为i节点到根节点的节点k次方之和
所以用dfs倍增递推求lca的板子,dfs时顺带求出每个幂次下该节点到根节点的幂次方之和
ans[v][i]=(ans[u][i]+mi[i])%mod
其中u是v的父亲节点,这是i次方下的转移方程
#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define pb push_back
#define endl "\n"
#define int long long
#define fi first
#define se second
//#pragma GCC optimize(3)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f;
const ll llmax=LLONG_MAX;
const int maxn=3e5+5;
const int mod=998244353;
int ans[maxn][51];//根到u的k次方和
int mi[51];
int k,n,m;
int dep[maxn];//存u的深度
int fa[maxn][50];//存从u向上跳pow(2,i)的祖先节点
//流程:1.dfs创建st表
//2.利用st表求LCA
vector<int>e[maxn];
void dfs(int u,int father){for(int i=1;i<=19;i++){fa[u][i]=fa[fa[u][i-1]][i-1];}for(int v:e[u]){if(v!=father){ dep[v]=dep[u]+1;fa[v][0]=u;for(int i=1;i<=50;i++){mi[0]=1;mi[i]=mi[i-1]*dep[v]%mod;ans[v][i]=(ans[u][i]+mi[i])%mod;}dfs(v,u);}}
} int lca(int u,int v){if(dep[u]<dep[v])swap(u,v);for(int i=19;i>=0;i--){if(dep[fa[u][i]]>=dep[v]){u=fa[u][i]; }if(u==v)return v; }for(int i=19;i>=0;i--){if(fa[u][i]!=fa[v][i]){u=fa[u][i];v=fa[v][i];}}return fa[u][0];
}void solve(){cin>>n;for(int i=1;i<=n-1;i++){int u,v;cin>>u>>v;e[u].pb(v);e[v].pb(u);} cin>>m;for(int i=2;i<=n;i++){ans[i][0]=1;}dfs(1,0);for(int i=1;i<=m;i++){int u,v;cin>>u>>v>>k;int zuxian=lca(u,v);int res=(ans[u][k]+ans[v][k]-ans[zuxian][k]-ans[fa[zuxian][0]][k]+2*mod)%mod;cout<<res<<endl;}
}signed main()
{ios::sync_with_stdio(false),cin.tie(0);int T=1;while(T--){solve();}return 0;
}