CF1076E Vasya and a Tree

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;
} 

还是挺简单的
离线大法吼哇!!

posted @ 2019-09-05 21:00  lahlah  阅读(19)  评论(0编辑  收藏  举报