zoukankan      html  css  js  c++  java
  • P4427 [BJOI2018]求和(倍增LCA、树链剖分)

    题目描述

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

    输入格式

    第一行包含一个正整数nn,表示树的节点数。

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

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

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

    树的节点从11 开始标号,其中11 号节点为树的根。

    输出格式

    对于每组数据输出一行一个正整数表示取模后的结果。

    题解:

    注意到k的范围只有50,所以先预处理出每个节点的深度k次前缀和,然后用树上差分的思想求出答案。求LCA用树剖或倍增LCA都可以。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=3e5+100;
    const ll mod=998244353;
    ll h[55][maxn];
    int n,m;
    vector<int> g[maxn];
    
    int father[20][maxn];
    ll db[55][maxn];//预处理所有数的k次
     
    void dfs (int x) {
        for (int i=0;i<g[x].size();i++) {
            int v=g[x][i];
            if (v==father[0][x]) continue;
            father[0][v]=x;
            h[0][v]=h[0][x]+1;
            for (int k=1;k<=50;k++)
                h[k][v]=h[k][x]+db[k][h[0][v]],
                h[k][v]%=mod;
            dfs(v);
        }
    }
    int lca (int x,int y) {
        if (h[0][x]<h[0][y]) swap(x,y);
        for (int i=17;i>=0;i--)
            if (h[0][x]-h[0][y]>>i) x=father[i][x];
        if (x==y) return x;
        for (int i=17;i>=0;i--) 
            if (father[i][x]!=father[i][y]) {
                x=father[i][x];
                y=father[i][y];
            }
        return father[0][x];
    }
    ll getDis (int x,int y,int k) {
        int Lca=lca(x,y);
        int lf=father[0][Lca];
        return (h[k][x]+h[k][y])%mod+2*mod-(h[k][Lca]+h[k][lf]);
    }
    
    int main () {
        scanf("%d",&n);
        for (int i=1;i<=n;i++) {
            db[1][i]=i;
            for (int j=2;j<=50;j++)    
                db[j][i]=db[j-1][i]*db[1][i],
                db[j][i]%=mod;
        }
        for (int i=1;i<n;i++) {
            int x,y;
            scanf("%d%d",&x,&y);
            g[x].push_back(y);
            g[y].push_back(x);
        }
        dfs(1);
        for (int i=1;i<=17;i++)
            for (int j=1;j<=n;j++)
                father[i][j]=father[i-1][father[i-1][j]];
        scanf("%d",&m);
        for (int i=1;i<=m;i++) {
            int x,y,k;
            scanf("%d%d%d",&x,&y,&k);
            printf("%lld
    ",(getDis(x,y,k)+mod)%mod);
        }
    }
  • 相关阅读:
    PAT Advanced 1067 Sort with Swap(0, i) (25分)
    PAT Advanced 1048 Find Coins (25分)
    PAT Advanced 1060 Are They Equal (25分)
    PAT Advanced 1088 Rational Arithmetic (20分)
    PAT Advanced 1032 Sharing (25分)
    Linux的at命令
    Sublime Text3使用指南
    IntelliJ IDEA创建第一个Groovy工程
    Sublime Text3 安装ftp插件
    Sublime Text3配置Groovy运行环境
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/13462848.html
Copyright © 2011-2022 走看看