P4427 [BJOI2018]求和

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/guapi2333/article/details/83513107

SDOI要有这么水的题就好了emmm

题意:给你一棵树。每一个点有一个点权w和深度deep(默认根节点深度为0)。w_{i}=deep_{i}下面给你q次询问,每个询问(u,v,k)表示询问点u到点v路过的所有点的权值的k次方之和。

数据范围:1\leq n,m\leq 300000,1\leq k\leq 50

分析:设数组sum[i][j]表示从根节点到点i(包括根节点和点i)经过的所有点的点权的k次方之和。那么对于每一次询问(u,v,k),答案便是:

sum[u][k]-sum[father[LCA(u,v)]][k]+sum[v][k]-sum[LCA(u,v)][k]

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;
}

猜你喜欢

转载自blog.csdn.net/guapi2333/article/details/83513107