zoukankan      html  css  js  c++  java
  • BZOJ 5293 求和(LCA)

    5293: [Bjoi2018]求和

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 203  Solved: 128
    [Submit][Status][Discuss]

    Description

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

    Input

    第一行包含一个正整数n ,表示树的节点数。
    之后n-1 行每行两个空格隔开的正整数i,j ,表示树上的一条连接点i 和点j 的边。
    之后一行一个正整数m ,表示询问的数量。
    之后每行三个空格隔开的正整数i,j,k ,表示询问从点i 到点j 的路径上所有节点深度的k 次方和。
    由于这个结果可能非常大,输出其对998244353 取模的结果。
    树的节点从1 开始标号,其中1 号节点为树的根。

    Output

    对于每组数据输出一行一个正整数表示取模后的结果。
    1≤n,m≤300000,1≤k≤50

    Sample Input

    5
    1 2
    1 3
    2 4
    2 5
    2
    1 4 5
    5 4 45

    Sample Output

    33
    503245989

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include <queue>
    #include <iostream>
    
    using namespace std;
    typedef long long LL;
    #define N 300005
    const int mod = 998244353;
    int pow(int a,int b){
        int odd = 1;
        while (b){
            if(b&1){
                odd = (int)(1ll*odd*a%mod);
            }
            a = (int)(1ll*a*a%mod);
            b>>=1;
        }
        return odd;
    }
    class Graphic {
    public:
        Graphic(){
            bin[0] =1;
            for(int i = 1 ; i < 25 ; ++i)bin[i] = bin[i-1]<<1;
        }
        void init(){
            cnt = 0;
            dep[1] = 1;
            fa[1][0] = 0;
            memset(head,-1, sizeof(head));
        }
        void pre_deal(){
            dfs(1);
            cal(1);
        }
        void add(int u,int v){
            _add(u,v);
            _add(v,u);
        }
        int find_sum(int x,int y,int rat){
            int la = lca(x,y);
            return int((nx[x][rat]+nx[y][rat]-nx[la][rat]-nx[fa[la][0]][rat])%mod);
        }
    private:
        struct Edge {
            int to, next;
        } edge[N << 1];
        int head[N],cnt;
        int bin[25];
        int dep[N],
            fa[N][25];///fa[i][j]表示 i的第 (1<<j)个父亲
        LL nx[N][52];///nx[i][j] 表示节点i的j次方和
        void _add(int u,int v){
            edge[cnt].to = v;
            edge[cnt].next = head[u];
            head[u] = cnt++;
        }
        int lca(int x,int y){
            if(dep[x]<dep[y])swap(x,y);
            for(int i=20;i>=0;i--)if(bin[i]<=dep[x] and dep[fa[x][i]]>=dep[y])x=fa[x][i];///将x y的深度调成相同的
            if(x==y)return x;
            for(int i=20;i>=0;i--)if(bin[i]<=dep[x] and fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
            return fa[x][0];
        }
        void cal(int x){
            for(int i = 1 ; i <= 50 ; ++i)nx[x][i] = nx[fa[x][0]][i]+pow(dep[x]-1,i);
            int v;
            for(int i = head[x] ; ~i ; i = edge[i].next){
                v = edge[i].to;
                if(v!=fa[x][0])cal(v);
            }
        }
        void dfs(int x){
            for(int i = 1 ; i <= 20 ; ++i){
                if(fa[x][i-1]){
                    fa[x][i] = fa[fa[x][i-1]][i-1];
                    /// x的第 2^i个父亲就是 x的2^(i-1)个父亲的2^(i-1)个父亲
                }
                else break;
            }
            int v;
            for(int i = head[x] ; ~i ;i = edge[i].next ){
                v = edge[i].to;
                if(v!=fa[x][0]){
                    fa[v][0] = x;
                    dep[v] = dep[x]+1;
                    dfs(v);
                }
            }
        }
    };
    Graphic ss;
    int main(){
        int n,m,a,b;
        while(cin>>n){
            ss.init();
            for(int i = 1 ; i < n ; ++i){
                scanf("%d %d",&a,&b);
                ss.add(a,b);
            }
            ss.pre_deal();
            cin>>m;
            int k;
            while (m--){
                scanf("%d %d %d",&a,&b,&k);
                printf("%d
    ",ss.find_sum(a,b,k));
            }
        }
    }
  • 相关阅读:
    WinForm获取窗体关闭原因和是否取消关闭值
    DIV CSS 居中代码(以及靠右)
    C#获取本机所有IP地址(包括局域网和本机外网IP)
    C# WinForm关闭窗体确认
    .NET WinForm全屏和退出以及蓝屏黑屏等
    HTML5标签
    C# 文件、文件夹操作语句(删除,创建,移动,检查是否存在)
    jquery聚焦文本框
    JS当前页面登录注册框,固定DIV,底层阴影
    Visual Studio 怎样添加引用
  • 原文地址:https://www.cnblogs.com/DevilInChina/p/9455013.html
Copyright © 2011-2022 走看看