CF1076E Vasya and a Tree
大意
给一个以 1 1 1为根的树,现在有 m m m个操作,每个操作读入 u , d e p , w u,dep,w u,dep,w表示 给以 u u u为根节点且距离 u u u小于 d e p dep dep范围上的点权值加 w w w.
题解
这题离线后就很好做了
首先把问题离线到树上的每个节点上
然后可以用树状数组维护深度上的权值和
具体还是看代码吧
#include<bits/stdc++.h>
#define N 1000005
#define int long long
#define lowbit(x) (x & -x)
using namespace std;
struct A{
int d, x;
};
vector<A> a[N];
struct edge{
int v, nxt;
}e[N];
int p[N], eid;
void init(){
memset(p, -1, sizeof p);
eid = 0;
}
void insert(int u, int v){
e[eid].v = v;
e[eid].nxt = p[u];
p[u] = eid ++;
}
int tree[N];
void update(int x, int y){
for(; x < N; x += lowbit(x)) tree[x] += y;
}
int query(int x){
int ret = 0;
for(; x; x -= lowbit(x)) ret += tree[x];
return ret;
}
int n, m, ANS[N];
void dfs(int u, int fa, int dep){//遍历整棵树
for(int i = 0; i < a[u].size(); i ++) update(min(n, dep + a[u][i].d), a[u][i].x);//把对应深度的权值加上
ANS[u] = query(n) - query(dep - 1);//计算答案
for(int i = p[u]; i + 1; i = e[i].nxt){
int v = e[i].v;
if(v == fa) continue;
dfs(v, u, dep + 1);//遍历
}
for(int i = 0; i < a[u].size(); i ++) update(min(n, dep + a[u][i].d), - a[u][i].x);//撤销操作
}
signed main(){
init();
scanf("%lld", &n);
for(int i = 1; i < n; i ++){
int u, v;
scanf("%lld%lld", &u, &v);
insert(u, v);
insert(v, u);
}
scanf("%lld", &m);
for(int i = 1; i <= m; i ++){
int u, d, x;
scanf("%lld%lld%lld", &u, &d, &x);
a[u].push_back(A{d, x});//把问题离线到树的节点上
}
dfs(1, 0, 1);
for(int i = 1; i <= n; i ++) printf("%lld ", ANS[i]);
return 0;
}
还是挺简单的
离线大法吼哇!!