Codeforces #447 Div2 D

Posted ftae

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

以上是关于Codeforces #447 Div2 D的主要内容,如果未能解决你的问题,请参考以下文章

codeforces 447 A-E div2 补题

Codeforces Round #393 div2

Codeforces #449 Div2 D

codeforces round #427 div2

codeforces round #428 div2

CodeForces #368 div2 D Persistent Bookcase DFS