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));
            }
        }
    }
  • 相关阅读:
    IOS Charles(代理服务器软件,可以用来拦截网络请求)
    Javascript中addEventListener和attachEvent的区别
    MVC中实现Area几种方法
    Entity Framework Code First 中使用 Fluent API 笔记。
    自定义JsonResult解决 序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    An entity object cannot be referenced by multiple instances of IEntityChangeTracker 的解决方案
    Code First :使用Entity. Framework编程(8) ----转发 收藏
    Code First :使用Entity. Framework编程(6) ----转发 收藏
    Code First :使用Entity. Framework编程(5) ----转发 收藏
  • 原文地址:https://www.cnblogs.com/DevilInChina/p/9455013.html
Copyright © 2011-2022 走看看