Educational Codeforces Round 54 E - Vasya and a Tree 树上:离线+dfs+树状数组

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xiang_6/article/details/84026790

题意:

给定一棵包含n个结点的树,开始每个结点权值为0,现在有q个操作,每个操作包含 v, d, x,表示第v号结点,以及再往下(对于树:他的孩子方向)遍历d层,访问到的结点权值都加上x;

输出所有结点的权值

思路:

一下想到的就是区间更新,单点查询,想写个树剖来着,感觉有点麻烦,然后就想到了树状数组很快的那个区间更新,前缀和当单点查询的操作,

然后再想想就想到了把所有操作离线出来,然后dfs遍历树的时候更新每个结点的操作,回溯的时候在更新回去,这样在更新到某个结点的时候,他的祖先结点的所有更新都全了;

复杂度O(n*log(maxn)+q)吧算是;

#include<bits/stdc++.h>
using namespace std;
#define out fflush(stdout);
#define fast ios::sync_with_stdio(0),cin.tie(0);
#define FI first
#define SE second
typedef long long ll;
typedef pair<ll,ll> P;
const int maxn = 3e5;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;

int n, m;
ll v, d, x;
vector<int> vec[maxn+7];

ll c[maxn + 7];
void add(int id, ll x) {
    for(int i = id; i <= maxn; i += (i&-i)) {
        c[i] += x;
    }
}
ll sum(int id) {
    ll res = 0;
    for(int i = id; i > 0; i -= (i&-i)) {
        res += c[i];
    }
    return res;
}

vector<P> q[maxn+7];
ll ans[maxn+7];

void dfs(int id, int cnt, int f) {
    for(auto i : q[id]) {
        ll d = i.FI, x = i.SE;
        add(cnt, x);
        add(cnt+d+1, -x);
    }
    ans[id] = sum(cnt);
    for(auto i : vec[id]) {
        if(i == f) continue;
        dfs(i, cnt+1, id);
    }
    for(auto i : q[id]) {
        ll d = i.FI, x = i.SE;
        add(cnt, -x);
        add(cnt+d+1, x);
    }
}

int main() {
    scanf("%d", &n);
    int u, v;
    for(int i = 1; i < n; ++i) {
        scanf("%d%d", &u, &v);
        vec[u].push_back(v);
        vec[v].push_back(u);
    }
    scanf("%d", &m);
    for(int i = 1; i <= m; ++i) {
        scanf("%lld%lld%lld", &v, &d, &x);
        q[v].push_back(P(d,x));
    }

    dfs(1, 1, -1);
    for(int i = 1; i <= n; ++i) {
        printf("%lld%c", ans[i], (i == n ? '\n' : ' '));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xiang_6/article/details/84026790
今日推荐