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));
            }
        }
    }
  • 相关阅读:
    暑假工作日志——关于51的串口的小问题
    C中怎么利用指针实现一个函数输入一个数组且输出一个数组
    2015.8.5数组与指针练习总结
    2015.8.5关于指针的个人理解
    2015.8.3keil调试遇到的问题
    2015.8.3stm32f4串口调试记录
    quartusII 错误记录
    3/4、事例三、四:透视投影(Perspective)、正射投影(Ortho)
    2、事例二: 三角形的几何变换平移(Translate)、旋转(Scale)、缩放(Rotate)
    1、事例一: 一个三角形、一个正方形(Vertex)
  • 原文地址:https://www.cnblogs.com/DevilInChina/p/9455013.html
Copyright © 2011-2022 走看看