CodeForces 1076E Vasya and a Tree(树上差分+树状数组)

原题地址:https://codeforces.com/contest/1076/problem/E

题意:给出一棵树,有 m m m次操作,每次操作有一个 v , d , x , v,d,x, v,d,x,表示将以 v v v为根节点,距离 v v v的长度小于等于 d d d的所有节点权值加上 x x x,最后求所有节点的权值。

思路:如果是对节点v的子树进行修改,那么问题可以用dfs序转化为序列上的问题,但是这题是对距离为d的进行修改,那么就需要用别的方法。

可以发现修改是区间上的修改,又由于问题是在树上的问题,可以考虑树上差分。我们可以知道,对于一次操作 v , d , x v,d,x v,d,x而言,如果节点v的深度是dep,那么v影响到的节点的深度必然是 [ d e p , d e p + d ] [dep,dep+d] [dep,dep+d],那么我们就可以对深度进行差分,由于 d f s dfs dfs只会往当前节点的子节点进行递归,所以不需要考虑相同深度当不属于v的子树中的点。

注意操作完之后还原现场即可。


#include 

#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define CLR(x, y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 3e5 + 5;
const int mod = 1e9 + 7;
/*
给你一棵n个点的树,以1为根。一开始n个点的权值为0,每个边的边长为1.
给你m个操作,每次给v,d,x。
把所有祖先是v的,且距离v不超过d的点的权值都加上x。
 */
int n, m, a[maxn];
const int N = 3e5 + 5;
ll bit[N];

int lowbit(int x) {
    return x & -x;
}

void add(int i, ll x) {
    while (i < N) {
        bit[i] += x;
        i += lowbit(i);
    }
}

ll query(int i) {
    ll sum = 0;
    while (i) {
        sum += bit[i];
        i -= lowbit(i);
    }
    return sum;
}

struct node {
    int v, nxt;
} e[2 * maxn];
int tot, head[maxn];

void add_edge(int u, int v) {
    e[tot].v = v;
    e[tot].nxt = head[u];
    head[u] = tot++;
}

struct nee {
    int d, x;
};
vector<nee> vec[maxn];

ll ans[maxn];

void dfs(int u, int fa, int dep) {
    int sz = vec[u].size();
    for (int i = 0; i < sz; i++) {

        int d = vec[u][i].d;
        int x = vec[u][i].x;


        add(dep, x);
        add(dep + d + 1, -x);
    }
    ans[u] = query(dep);
    for (int i = head[u]; ~i; i = e[i].nxt) {
        int v = e[i].v;
        if (v == fa)continue;
        dfs(v, u, dep + 1);
    }
    for (int i = 0; i < sz; i++) {
        int d = vec[u][i].d;
        int x = vec[u][i].x;
        add(dep, -x);
        add(dep + d + 1, x);
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
    CLR(head, -1);
    scanf("%d", &n);
    for (int i = 1; i < n; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        add_edge(u, v);
        add_edge(v,u);
    }
    scanf("%d", &m);
    for (int i = 1; i <= m; i++) {
        int v, d, x;
        scanf("%d%d%d", &v, &d, &x);
        vec[v].push_back(nee{d, x});
    }
    dfs(1, 1, 1);


    for (int i = 1; i <= n; i++) printf("%lld ", ans[i]);
    return 0;
}


你可能感兴趣的:(ACM_数据结构)