版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/guapi2333/article/details/83513107
SDOI要有这么水的题就好了emmm
题意:给你一棵树。每一个点有一个点权和深度(默认根节点深度为0)。下面给你次询问,每个询问表示询问点到点路过的所有点的权值的次方之和。
数据范围:。
分析:设数组表示从根节点到点(包括根节点和点)经过的所有点的点权的次方之和。那么对于每一次询问,答案便是:
Code:
#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=300020,KMAXN=52;
const long long MOD=998244353;
int n,m,u[MAXN<<1],v[MAXN<<1],first[MAXN<<1],nxt[MAXN<<1],q,a,b,num;
int fa[MAXN][21];
long long deep[MAXN][KMAXN],sum[MAXN][KMAXN];
inline int read()
{
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while('0'<=ch&&ch<='9')
{
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
return x;
}
void dfs(int x,int father,long long dep)
{
deep[x][1]=dep;fa[x][0]=father;
for(int i=2;i<=50;i++) deep[x][i]=(deep[x][i-1]*dep)%MOD;
for(int i=1;i<=50;i++) sum[x][i]=(sum[father][i]+deep[x][i])%MOD;
for(int i=1;(1<<i)<=(int)deep[x][1];i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int k=first[x];k>0;k=nxt[k])
if(v[k]!=father) dfs(v[k],x,dep+1);
}
long long LCA(int x,int y,int k)
{
if(x==y) return deep[x][k];
if(deep[x][1]<deep[y][1]) swap(x,y);
int fstx=x,fsty=y;
int step=(int)deep[x][1]-deep[y][1];
for(int i=20;i>=0;i--)
if(step&(1<<i)) x=fa[x][i];
if(x==y) return (sum[fstx][k]-sum[fa[x][0]][k]+MOD)%MOD;
for(int i=20;i>=0;i--)
if(fa[x][i]!=fa[y][i]) { x=fa[x][i],y=fa[y][i]; }
x=fa[x][0];
return ((sum[fstx][k]-sum[fa[x][0]][k]+MOD)%MOD+(sum[fsty][k]-sum[fa[y][0]][k]+MOD)%MOD)%MOD;
}
void work()
{
n=read();
m=(n-1)<<1;
for(int i=1;i<=m;i+=2)
{
u[i]=read(),v[i]=read();
nxt[i]=first[u[i]],first[u[i]]=i;
u[i+1]=v[i],v[i+1]=u[i];
nxt[i+1]=first[u[i+1]],first[u[i+1]]=i+1;
}
}
int main()
{
work();
dfs(1,0,0);
q=read();
for(int i=1;i<=q;i++)
{
a=read(),b=read(),num=read();
cout<<LCA(a,b,num)<<'\n';
}
return 0;
}