zoukankan      html  css  js  c++  java
  • [POI2015] Odwiedziny

    [题目链接]

              https://www.lydsy.com/JudgeOnline/problem.php?id=4381

    [算法]

            考虑分块 , 先设一个阈值B = 200

            记Su , i表示从u节点开始 , 每次向上跳i步 , 所经过点的权值和 , 可以在O(NBlogN)时间内预处理

            对于每次询问 , 若k <= B , 可以通过预处理的值求出答案 , 否则暴力处理

            时间复杂度 : O(NBlogN)(取B = 200)

    [代码]

           

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    #define N 50010
    #define M 250
    #define MAXLOG 20
    
    struct edge {
            int to , nxt;
    } e[N << 1];
    
    int n , tot , MAGIC;
    int a[N] , b[N] , c[N] , father[N][MAXLOG] , depth[N] , head[N];
    ll cnt[N][M];
    
    template <typename T> inline void chkmax(T &x,T y) { 
            x = max(x,y); 
    }
    template <typename T> inline void chkmin(T &x,T y) { 
            x = min(x,y); 
    }
    template <typename T> inline void read(T &x) {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    inline void addedge(int u , int v) {
            ++tot;
            e[tot] = (edge){v , head[u]};
            head[u] = tot;
    }
    inline void work(int u , int par) {
            father[u][0] = par;
            depth[u] = depth[par] + 1;
            for (int i = 1; i < MAXLOG; ++i) {
                    father[u][i] = father[father[u][i - 1]][i - 1];
            }        
            for (int i = head[u]; i; i = e[i].nxt) {
                    int v = e[i].to;
                    if (v == par) continue;
                    work(v , u);
            }
    }
    inline int get(int u , int k) {
            for (int i = 0; i < MAXLOG; ++i) {
                    if (k & (1 << i))
                          u = father[u][i];
            }
            return u;
    }
    inline void dfs(int u , int par) {
            for (int i = 1; i <= MAGIC; ++i) {
                    cnt[u][i] = a[u] + cnt[get(u , i)][i];
            }
            for (int i = head[u]; i; i = e[i].nxt) {
                    int v = e[i].to;
                    if (v == par) continue;
                    dfs(v , u);
            }
    }
    inline int lca(int x , int y) {
            if (depth[x] > depth[y]) swap(x , y);
            for (int i = MAXLOG - 1; i >= 0; --i) {
                    if (depth[father[y][i]] >= depth[x])
                            y = father[y][i];
            }        
            if (x == y) return x;
            for (int i = MAXLOG - 1; i >= 0; --i) {
                    if (father[x][i] != father[y][i])
                            x = father[x][i] , y = father[y][i];
            }
            return father[x][0];
    }
    
    int main()
    {
            
            read(n);
            for (int i = 1; i <= n; ++i) read(a[i]);
            for (int i = 1; i < n; ++i) {
                    int x , y;
                    read(x); read(y);
                    addedge(x , y);
                    addedge(y , x);
            }
            for (int i = 1; i <= n; ++i) read(b[i]);
            for (int i = 2; i <= n; ++i) read(c[i]);
            MAGIC = (int)sqrt(n);
            work(1 , 0);
            dfs(1 , 0);
            for (int i = 2; i <= n; ++i) {
                    int x = b[i - 1] , y = b[i];
                    int Lca = lca(x , y);
                    ll ans = 0;
                    if (Lca == x) {
                            if (c[i] <= MAGIC) {
                                    int R = (depth[y] - depth[x]) % c[i];
                                    if (R > 0) ans += a[y];
                                    y = get(y , R);
                                    int val = (depth[y] - depth[x]) / c[i] + 1;
                                    ans += cnt[y][c[i]] - cnt[get(y , val * c[i])][c[i]]; 
                            } else {
                                    int R = (depth[y] - depth[x]) % c[i];
                                    if (R > 0) ans += a[y];
                                    y = get(y , R);
                                    while (depth[y] >= depth[x]) {
                                            ans += a[y];
                                            y = get(y , c[i]);
                                    }
                            }
                    } else if (Lca == y) {
                            if (c[i] <= MAGIC) {
                                    int val = (depth[x] - depth[y]) / c[i] + 1;
                                    ans += cnt[x][c[i]] - cnt[get(x , val * c[i])][c[i]];
                            } else {
                                    while (depth[x] >= depth[y]) {
                                            ans += a[x];
                                            x = get(x , c[i]);
                                    }
                            }
                    } else if (c[i] <= MAGIC) {
                            int val = (depth[x] - depth[Lca]) / c[i] + 1;
                            ans += cnt[x][c[i]] - cnt[get(x , val * c[i])][c[i]];
                            int pre = get(x , (val - 1) * c[i]);
                            int R = (depth[pre] - depth[Lca] + depth[y] - depth[Lca]) % c[i];
                            if (R != 0) {
                                    int now = get(y , R);
                                    val = (depth[now] - depth[Lca]) / c[i] + 1;
                                    ans += a[y] + cnt[y][c[i]] - cnt[get(y , val * c[i])][c[i]]; 
                            } else {
                                    val = (depth[y] - depth[Lca]) / c[i] + 1;
                                    ans += cnt[y][c[i]] - cnt[get(y , val * c[i])][c[i]];
                                    if ((depth[x] - depth[Lca]) % c[i] == 0) ans -= a[Lca];
                            } 
                    } else {
                            while (depth[x] >= depth[Lca]) {
                                    ans += a[x];
                                    if (depth[x] - c[i] < depth[Lca]) break;
                                    else x = get(x , c[i]);
                            }
                            int R = (depth[x] - depth[Lca] + depth[y] - depth[Lca]) % c[i];
                            if (R != 0) {
                                    ans += a[y];
                                    y = get(y , R);
                                    while (depth[y] >= depth[Lca]) {
                                            ans += a[y];
                                            y = get(y , c[i]);
                                    }
                            } else {
                                    while (depth[y] >= depth[Lca]) {
                                            ans += a[y];
                                            y = get(y , c[i]);
                                    }
                                    if (x == Lca) ans -= a[Lca];
                            }
                    }
                    printf("%lld
    " , ans);
            }
            
            return 0;
        
    }
  • 相关阅读:
    USACO2018 DEC(Platinum) (树上乱搞,期望+凸包)
    USACO2018 DEC (Gold) (dp,容斥+哈希,最短路)
    《信息学奥赛一本通》题库 1034 计算三角形面积——基础
    UNR#3 Day1——[ 堆+ST表+复杂度分析 ][ 结论 ][ 线段树合并 ]
    bzoj 4298 [ONTAK2015]Bajtocja——哈希+启发式合并
    玲珑杯#20 C 漆黑的太阳——莫队
    链表写法
    传址函数写法
    bzoj 4650 & 洛谷 P1117 优秀的拆分 —— 枚举关键点+后缀数组
    bzoj 2119 股市的预测 —— 枚举关键点+后缀数组
  • 原文地址:https://www.cnblogs.com/evenbao/p/10778232.html
Copyright © 2011-2022 走看看