E. Vasya and a Tree(树上主席树or树上可持续化线段树)

E. Vasya and a Tree

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

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

Copy

5
1 2
1 3
2 4
2 5
3
1 1 1
2 0 10
4 10 100

output

Copy

1 11 1 100 0 

input

Copy

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

Copy

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.

来看看许老师的解法:

传送门

题目传送门

树上主席树?我咋感觉是树上可持续化的线段树,线段树以深度为下标保存个数,但是代码里更新的操作的确很像主席树模板的操纵,但是查询就不是主席树的操作了,就是普通的线段树求和的操作。嗯!更加确定我的感觉,是可持续化线段树。

感觉许老师随便一个代码就可以够我学一天的了,这个题我搞了就快一天了,dfs那里看了一遍又一遍,查询和更新都没有什么大的变化。

在许老师代码上加了注释,防止生涩难懂

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=3e5+10;
ll sum[maxn*20],ans[maxn];
int ls[maxn*20],rs[maxn*20],cnt=0,n;
struct node
{
	int d,x;
	node(int a,int b)
	{
		d=a,x=b;
	}
};
vector<node>q[maxn];
vector<int>G[maxn];
void up(int pre,int &o,int l,int r,int k,int v)//以深度为位置更新? 
{
	o=++cnt;
	ls[o]=ls[pre],rs[o]=rs[pre];
	sum[o]=sum[pre]+v;
	if(l==r)return;
	int m=(l+r)/2;
	if(k<=m)up(ls[pre],ls[o],l,m,k,v);
	else up(rs[o],rs[o],m+1,r,k,v);
}
//给每个结点建一个主席树还是什么鬼 
//给每一个所能达到的最大深度建立一颗可持续化的线段树 
ll qu(int o,int l,int r,int k)
{
	if(l>=k&&r<=n||!sum[o])return sum[o];//如果已经是零了,没必要继续往下了,除非有负数 
	int m=(l+r)/2;
	ll res=0;
	if(n>m) res=qu(rs[o],m+1,r,k);//肯定成立 
	if(k<=m)res+=qu(ls[o],l,m,k);// 
	return res; 
}
void dfs(int u,int pre,int fa,int dep)//从结点为1的开始建树,树上主席树,真的是有点妙 
{
	int rt=0;//每到一个结点都要新开辟一个主席树?有点猛 
	//它有回溯的情况,可以要记录历史情况,bfs可以吗,也不行 ,不能共享,那还是主席树吧 
	//感觉像是可持续化线段树,可持续化后是记录最后一个
	for(int i=0;i<q[u].size();i++)
	{
		int k=min(n,q[u][i].d+dep);//能达到的最大深度 
		if(!rt)up(pre,rt,1,n,k,q[u][i].x);//直接更新能达到最深的点,艾玛太秀了 
		else up(rt,rt,1,n,k,q[u][i].x);// 
	}
	if(!rt)rt=pre;//这里的确是记录的最后一个,只是防止他没有创立新的树,就继承上一个的树 
	ans[u]=qu(rt,1,n,dep);//类似差分
	for(int i=0;i<G[u].size();i++)//继续往下走吧 
	if(G[u][i]!=fa)
	dfs(G[u][i],rt,u,dep+1);//子树全部继承父亲结点的最后一个主席树,嗯,很妙 
}
int main()
{
	int u,v,x,op;
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	scanf("%d",&op);
	while(op--)
	{
		scanf("%d%d%d",&u,&v,&x);
		v=min(v,n);//有必要吗?似乎有//叶子结点以n为下限,免得不知道主席树开多大 
		q[u].push_back(node(v,x));
	}
	dfs(1,0,0,1); //哎呀妈呀你也太秀了吧 
	for(int i=1;i<n;i++)printf("%I64d ",ans[i]);
	printf("%I64d\n",ans[n]);
}

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/89438091