BZOJ5293&&洛谷P4427[BZOI2018]求和

一眼看上去LCA+暴力,emm30分,弃疗

然后发现这道题不用修改,也就是说我们可以提前预处理出所有的pow(i,k),我们定义po[i][k]表示i在k次方意义下的前缀和,也就是说从根到i在k次方意义下的前缀和,然后后面取出的时候,要减去不在u->v路径上的部分,直接查表就好

代码

//By AcerMo
#include<cmath> 
#include<cstdio> 
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int mod=998244353;
const int M=300500;
int n,m;
int dep[M],f[M][21];
long long int po[M][55];
vector<int>v[M];
inline int read()
{
	int x=0;char ch=getchar();
	while (ch>'9'||ch<'0') ch=getchar();
	while (ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar();
	return x; 
}
inline long long int fpow(long long int a,long long int b)
{
	long long int ans=1;
	for (;b;a=(a*a)%mod,b>>=1)
		if (b&1) ans=(ans*a)%mod;
	return ans%mod; 
}
inline void dfs(int x,int fa)
{
	dep[x]=dep[fa]+1;f[x][0]=fa;
	for (int i=1;i<=50;i++)
		po[x][i]=(po[fa][i]+fpow(dep[x],i));
	for (int i=0;i<v[x].size();i++)
	{
		int go=v[x][i];
		if (go!=fa) dfs(go,x);
	}
	return ;
}
inline void getf()
{
	for (int j=1;j<=20;j++)
	for (int i=1;i<=n;i++)
	f[i][j]=f[f[i][j-1]][j-1];
	return ;
}
inline int LCA(int x,int y)
{
	if (dep[x]<dep[y]) swap(x,y);
	for (int i=20;i>=0;i--)
		if (dep[f[x][i]]>=dep[y])
			x=f[x][i];
	if (x==y) return x;
	for (int i=20;i>=0;i--)
		if (f[x][i]!=f[y][i])
			x=f[x][i],y=f[y][i];
	return f[x][0];
}
int main()
{
	n=read();int x,y,z;
	for (int i=1;i<n;i++) 
	{
		x=read(),y=read();
		v[x].push_back(y);
		v[y].push_back(x);
	}
	dep[1]=-1;dfs(1,1);getf();m=read();
	for (int i=1;i<=m;i++)
	{
		x=read();y=read();z=read();
		int lca=LCA(x,y);
		printf("%lld\n",(po[x][z]+po[y][z]-po[lca][z]-po[f[lca][0]][z])%mod);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/acerandaker/article/details/80959649