求和(洛谷P[4427],BJOI[2018],LCA)

    xiaoxiao2024-10-21  73

    文章目录

    题目思路心得代码


    题目

    描述 master 对树上的求和非常感兴趣。他生成了一棵有根树,并且希望多次询问这棵树上一段路径上所有节点深度的k 次方和,而且每次的k 可能是不同的。此处节点深度的定义是这个节点到根的路径上的边数。他把这个问题交给了pupil,但pupil 并不会这么复杂的操作,你能帮他解决吗? 输入 第一行包含一个正整数 n n n,表示树的节点数。

    之后 n − 1 n-1 n1行每行两个空格隔开的正整数 i , j i, j i,j表示树上的一条连接点 i i i 和点 j j j 的边。

    之后一行一个正整数 m m m,表示询问的数量。

    之后每行三个空格隔开的正整数 i , j , k i, j, k i,j,k表示询问从点i 到点j 的路径上所有节点深度的 k k k 次方和。由于这个结果可能非常大,输出其对 998244353 998244353 998244353 取模的结果。

    树的节点从 1 1 1开始标号,其中 1 1 1号节点为树的根。 输出 对于每组数据输出一行一个正整数表示取模后的结果 样例输入 5 1 2 1 3 2 4 2 5 2 1 4 5 5 4 45 样例输出 33 503245989 范围 对于 100 % 100\% 100%的数据, 1 ≤ n , m ≤ 300000 , 1 ≤ k ≤ 50 1 \leq n,m \leq 300000, 1 \leq k \leq 50 1n,m300000,1k50

    思路

    我们要求 i i i j j j之间所有点的深度的 k k k次方和,那一定会经过它们的 L C A LCA LCA。那就可以转换为两部分,一是 i i i点到 L C A LCA LCA之间所有点深度的 k k k次方和,二是 j j j点到 L C A LCA LCA之间所有点深度的 k k k次方和。而 i i i点到 L C A LCA LCA之间所有点深度的 k k k次方和就可以转换为i到根节点的所有深度的 k k k次方和减去 L C A LCA LCA到根节点所有深度的 k k k次方和, j j j点也相同 因为每条路径上每种深度是唯一的,因此你暴力把每种深度的 1 1 1~ 50 50 50次方都打出来,在搞个前缀和就行了。 注意, L C A LCA LCA的深度被减光了,因此还要加上一个 L C A LCA LCA深度的 k k k次方

    心得

    若果你在洛谷上一直40分,且是后面三个点和第三个点过,其他WA,我建议你重打,且在遍历树的时候就把前缀和搞出来(反正我是这样过的)

    代码

    #include <cstdio> #include <vector> #include <iostream> using namespace std; #define mod 998244353 #define M 300005 #define LL long long vector<int>G[M]; int n, m, s, e, k; int f[M][22], dep[M]; LL p[M][55], d[M][55]; bool v[M]; inline int maxx(int x, int y){ return x > y? x: y; } inline LL qkp(LL x, LL y){ LL sum = 1; while( y ){ if( y&1 ) sum = sum*x%mod; x = x*x%mod; y >>= 1; } return sum; } inline void dfs(int x, int last, int depth){ v[x] = 1; f[x][0] = last; dep[x] = depth; for(int i = 0; i < 51; i ++){ d[depth][i] = qkp(depth, i); p[depth][i] = (p[maxx(0,depth-1)][i]+d[depth][i])%mod; } for(int i = 1; i < 19; i ++) f[x][i] = f[f[x][i-1]][i-1]; int siz = G[x].size(); for(int i = 0; i < siz; i ++){ int son = G[x][i]; if( !v[son] ) dfs(son, x, depth+1); } } inline int LCA(int x, int y){ for(int i = 18; i >= 0; i --){ if( dep[f[x][i]] >= dep[y] ) x = f[x][i]; if( dep[f[y][i]] >= dep[x] ) y = f[y][i]; } if( x != y ){ for(int i = 18; i >= 0; i --){ if( f[x][i] != f[y][i] ) x = f[x][i], y = f[y][i]; } x = f[x][0]; } return x; } int main(){ scanf("%d", &n); for(int i = 1; i < n; i ++){ scanf("%d%d", &e ,&s); G[e].push_back(s); G[s].push_back(e); } dfs(1, 0, 0); scanf("%d", &m); while( m-- ){ scanf("%d%d%d", &s, &e, &k); int lca = LCA(s, e); printf("%lld\n", (((p[dep[s]][k]-p[dep[lca]][k]+mod)%mod + (p[dep[e]][k]-p[dep[lca]][k]+mod)%mod)%mod + d[dep[lca]][k])%mod ); } return 0; }
    最新回复(0)