Vasya and a Tree CodeForces - 1076E(树状数组+dfs)

Vasya has a tree consisting of nn vertices with root in vertex 11. At first all vertices has 00 written on it.

Let d(i,j)d(i,j) be the distance between vertices ii and jj, i.e. number of edges in the shortest path from ii to jj. Also, let’s denote kk-subtree of vertex xx — set of vertices yy such that next two conditions are met:

xx is the ancestor of yy (each vertex is the ancestor of itself);
d(x,y)≤kd(x,y)≤k.
Vasya needs you to process mm queries. The ii-th query is a triple vivi, didi and xixi. For each query Vasya adds value xixi to each vertex from didi-subtree of vivi.

Report to Vasya all values, written on vertices of the tree after processing all queries.

Input
The first line contains single integer nn (1≤n≤3⋅1051≤n≤3⋅105) — number of vertices in the tree.

Each of next n−1n−1 lines contains two integers xx and yy (1≤x,y≤n1≤x,y≤n) — edge between vertices xx and yy. It is guarantied that given graph is a tree.

Next line contains single integer mm (1≤m≤3⋅1051≤m≤3⋅105) — number of queries.

Each of next mm lines contains three integers vivi, didi, xixi (1≤vi≤n1≤vi≤n, 0≤di≤1090≤di≤109, 1≤xi≤1091≤xi≤109) — description of the ii-th query.

Output
Print nn integers. The ii-th integers is the value, written in the ii-th vertex after processing all queries.

Examples
Input
5
1 2
1 3
2 4
2 5
3
1 1 1
2 0 10
4 10 100
Output
1 11 1 100 0
Input
5
2 3
2 1
5 4
3 4
5
2 0 4
3 10 1
1 2 3
2 3 10
1 1 7
Output
10 24 14 11 11
Note
In the first exapmle initial values in vertices are 0,0,0,0,00,0,0,0,0. After the first query values will be equal to 1,1,1,0,01,1,1,0,0. After the second query values will be equal to 1,11,1,0,01,11,1,0,0. After the third query values will be equal to 1,11,1,100,01,11,1,100,0.
一个小技巧,像这种题,如果输入全是一种操作,那么有可能是离线操作。。
给你一棵树,并有m次查询。每个查询是把以顶点为x的子树,并且离x不超过d,把这些节点的值都增加v(包括x)。
一开始没啥好思路,就是直接dfs序之后,线段树维护了一个深度最小值,然后去类似于单点更新去更新。第七个样例就TLE了。泪奔。。
这个思路为什么会超时呢?想一下,我们这么建立线段树是以dfs序为依据的。我们在更新的时候不能一个区间这样去更新,正因为这样就成了单点更新了,必TLE。
有没有什么技巧能一个区间一个区间的去更新?假如我们以深度为依据,这样去建立线段树,当到达一个节点后,我们把这个节点的深度dep~dep+d给更新了,因为我们离线操作了,这样就直接可以把以这个节点为头结点的操作全都执行完。执行完之后就直接可以求出这个节点最终的结果。因为我们是按着深度来的,这个深度的节点不光一个,所以执行完一个节点之后我们就得把之前的操作给清除了。树上差分,树状数组/线段树都可以。
代码如下:

#include
#define ll long long
using namespace std;

const int maxx=3e5+100;
struct node{
	int l;
	int r;
	ll sum;
	ll lazy;
	int dep;
}p[maxx<<2];
struct edge{
	int to;
	int next;
}e[maxx];
int head[maxx<<1];
int tot,n,m,sign,deep[maxx];ll ans[maxx];
ll c[maxx];
vector<pair<int,ll> >r[maxx];
/*--------------事前准备--------------*/ 
inline void add(int u,int v)
{
	e[tot].to=v,e[tot].next=head[u],head[u]=tot++;
}
inline void init()
{
	tot=sign=0;
	memset(head,-1,sizeof(head));
}
/*---------------树状数组----------------*/
inline int lowbit(int x){return x&-x;}
inline void update(int cur,ll v){while(cur<=maxx) c[cur]+=v,cur+=lowbit(cur);}
inline ll getsum(int cur){ll sum=0;while(cur>0) sum+=c[cur],cur-=lowbit(cur);return sum;}
/*---------------dfs----------------*/
inline void dfs(int u,int f)
{
	deep[u]=deep[f]+1;
	for(int i=0;i<r[u].size();i++)
	{
		update(deep[u],r[u][i].second);
		if(deep[u]+r[u][i].first+1<=n) update(deep[u]+r[u][i].first+1,-r[u][i].second);
	}
	ans[u]=getsum(deep[u]);
	for(int i=head[u];i!=-1;i=e[i].next)
	{
		int to=e[i].to;
		if(to==f) continue;
		dfs(to,u);
	}
	for(int i=0;i<r[u].size();i++)
	{
		update(deep[u],-r[u][i].second);
		if(deep[u]+r[u][i].first+1<=n) update(deep[u]+r[u][i].first+1,r[u][i].second);
	}
}
int main()
{
	int x,y;ll z;
	while(~scanf("%d",&n))
	{
		init();
		for(int i=1;i<n;i++)
		{
			scanf("%d%d",&x,&y);
			add(x,y);
			add(y,x);
		}
		scanf("%d",&m);
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d%lld",&x,&y,&z);
			r[x].push_back(make_pair(y,z));
		}
		deep[0]=0;
		dfs(1,0);
		for(int i=1;i<=n;i++) printf("%lld%c",ans[i],i==n?'\n':' ');
	}
	return 0;
}

努力加油a啊,(o)/~

你可能感兴趣的:(dfs,树状数组)