2018 icpc 沈阳网络赛J KaChang

http://www.cnblogs.com/Asm-Definer/p/9610262.html

这篇博客解释的非常好,我在这篇基础上再做解释:

树状数组的下标对应dfs序列,维护的自然是一段dfs序列的和,树状数组一次更新深度为L的T个点,每次更新的复杂度是logN,查询是查一个点,计算一段dfs序列的权值和,复杂度是logN。

利用lazy标记在更新的时候是O(1),但是在询问时需要访问所有已经有过lazy标记的层,这个层数不超过O(N/T)。

然后Q个操作就是Q(TlogN+N/T)。

这个T毫无疑问在取N/logN的时候复杂度最小,也就是Q(N+logN)。

做法太妙了,第一次接触这种题。

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
ll tree[maxn];
ll lazy[maxn];
int st[maxn], ed[maxn];
vector<int> G[maxn];
vector<int> depth[maxn];
vector<int> layer;

int timing = 0, max_dep = 0;
void dfs(int u, int dep) {
    max_dep = max(dep,max_dep);
    st[u] = ++timing;
    depth[dep].push_back(timing);
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        dfs(v,dep+1);
    }
    ed[u] = timing;
}

int lowbit(int x) {
    return x & -x;
}
void add(int x, ll a)  {
    while (x <= maxn) {
        tree[x] += a;
        x += lowbit(x);
    }
}
ll sum(int x) {
    ll ret = 0;
    while (x > 0) {
        ret += tree[x];
        x -= lowbit(x);
    }
    return ret;
}

int main() {
    int n, q, u, v, op, l, x;
    long long a;
    scanf("%d%d",&n,&q);
    for (int i = 1; i < n; i++) {
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
    }
    for(int i = 0; i <= n; i++) depth[i].clear();
    dfs(1,0);
    int valve = n/log(n);
    for (int i = 0; i <= max_dep; i++) {
        if(depth[i].size() >= valve)
            layer.push_back(i);
    }
    for (int i  = 0; i < q; i++) {
        scanf("%d",&op);
        if(op&1) {
            scanf("%d%lld",&l,&a);
            if (depth[l].size() < valve) {
                for (int i = 0; i < depth[l].size(); i++) {
                    add(depth[l][i],a);
                }
            }
            else {
                lazy[l] += a;
                // layer.push_back(l); 为什么不能在这边更新layer?因为多次更新同一层会造成会导致计算答案时被重复计算
            }
        }
        else {
            scanf("%d",&x);
            ll ans = 0;
            ans += sum(ed[x])-sum(st[x]-1);
            for (int i = 0; i < layer.size(); i++) {
                int deep = layer[i];
                ans += lazy[deep] * (upper_bound(depth[deep].begin(), depth[deep].end(), ed[x]) -   lower_bound(depth[deep].begin(), depth[deep].end(), st[x]));
            }
            printf("%lld\n",ans);
        }
    }
    return  0;
}

猜你喜欢

转载自www.cnblogs.com/Rickenqi/p/9635938.html