• Codeforces #447 Div2 D


    #447 Div2 D

    题意

    给一棵完全二叉树,每条边有权值为两点间的距离,每次询问 (x, h) ,从结点 (x) 出发到某一结点的最短路的距离 (d) 如果小于 (h) ,则答案加上 (h - d) ,考虑所有结点并输出答案。

    分析

    通过建树过程可以发现这是一棵完全二叉树,也就是说树很矮。
    可以预处理这棵树,对于每一个结点,我们可以计算出以这个结点为根结点的子树中的所有结点到当前子树的根结点的距离,从根结点向下 DFS 即可,然后自下而上合并,类似归并排序合并的过程。再预处理下前缀和,这样就很容易求得子树中有多少结点到根结点的距离小于 (h) ,向上走 (log(n)) 次一定可以到根结点。

    完全二叉树 很矮!祖先结点很少!很多情况都可以遍历(暴力)祖先结点!

    code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e6 + 10;
    int f, s, mx;
    int n, m, a[N], l[N], r[N];
    vector<int> G[N];
    vector<ll> S[N];
    void mergeUp(int rt, int cl, int cr) {
        int i = 0, j = 0;
        while(i < cl || j < cr) {
            if(i == cl) G[rt].push_back(r[j++]);
            else if(j == cr) G[rt].push_back(l[i++]);
            else {
                if(l[i] < r[j]) G[rt].push_back(l[i++]);
                else G[rt].push_back(r[j++]);
            }
        }
        ll sum = 0;
        for(int i = 0; i < G[rt].size(); i++) {
            sum += G[rt][i];
            S[rt].push_back(sum);
        }
    }
    void build(int rt) {
        if(rt >= s - mx + 1) return;
        build(rt * 2);
        build(rt * 2 + 1);
        int cl = 0, cr = 0;
        if(rt * 2 <= n) for(int i = 0; i < G[rt * 2].size(); i++) {
            l[cl++] = G[rt * 2][i] + a[rt * 2];
        }
        if(rt * 2 + 1 <= n) for(int i = 0; i < G[rt * 2 + 1].size(); i++) {
            r[cr++] = G[rt * 2 + 1][i] + a[rt * 2 + 1];
        }
        if(cl + cr > 0) mergeUp(rt, cl, cr);
    }
    int main() {
        scanf("%d%d", &n, &m);
        s = 1, mx = 1, f = 0;
        while(s < n) {
            mx *= 2;
            s += mx;
            f++;
        }
        for(int i = 1; i < n; i++) {
            int x;
            scanf("%d", &x);
            a[i + 1] = x;
            G[i].push_back(0);
        }
        G[n].push_back(0);
        build(1);
        while(m--) {
            int now, h, pre = -1;
            scanf("%d%d", &now, &h);
            ll ans = h;
            while(now) {
                if(now != 1 && a[now] < h) ans += h - a[now];
                if(pre == -1) {
                    int pos = lower_bound(G[now].begin(), G[now].end(), h) - G[now].begin() - 1;
                    if(pos > 0) ans += 1LL * pos * h - S[now][pos];
                } else {
                    if(now * 2 == pre && now * 2 + 1 <= n) {
                        int nxt = now * 2 + 1;
                        int pos = lower_bound(G[nxt].begin(), G[nxt].end(), h - a[nxt]) - G[nxt].begin() - 1;
                        if(pos > 0) ans += 1LL * pos * (h - a[nxt]) - S[nxt][pos];
                        if(a[nxt] < h) ans += h - a[nxt];
                    } else if(now * 2 + 1 == pre && now * 2 <= n) {
                        int nxt = now * 2;
                        int pos = lower_bound(G[nxt].begin(), G[nxt].end(), h - a[nxt]) - G[nxt].begin() - 1;
                        if(pos > 0) ans += 1LL * pos * (h - a[nxt]) - S[nxt][pos];
                        if(a[nxt] < h) ans += h - a[nxt];
                    }
                }
                h -= a[now];
                pre = now;
                now /= 2;
            }
            cout << ans << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    2277 爱吃皮蛋的小明
    zoj2314 经典 无源汇有上下界最大流 并输出可行流
    [置顶] css3 befor after 简单使用 制作时尚焦点图相框
    [置顶] 程序员的奋斗史(二十八)——寒门再难出贵子?
    TaintDroid:智能手机监控实时隐私信息流跟踪系统(四)
    Activity切换效果(overridePendingTransition)
    Activity生命周期,状态保存恢复(经典)
    大二实习使用的技术汇总(上)
    Struts2配置RESULT中TYPE的参数说明
    关于程序动态库链接和运行时搜索路径设置的个人理解
  • 原文地址:https://www.cnblogs.com/ftae/p/7875241.html
Copyright © 2020-2023  润新知