列表

详情


NC215082. 树

描述

给你一个含有n个结点的树,1号点为根结点,有n - 1条边, 每个结点都有一个权值,现在你有3种操作:

1 u,表示询问以u为根结点的子树所有点的权值和。

2 u v,表示将以u为根结点的子树所有点的权值都加v。

3 u v,表示将以u结点的所有儿子结点权值都加v(包括u结点本身)。

输入描述

第一行两个整数 n   q,表示n个结点,q次操作。

第二行n个整数,表示每个点的权值。

接下来n - 1行两个整数,u v,表示u到v有一条无向边(保证数据构成一颗树)。

接下来q行,每行为题目描述提到的的3种格式之一,表示一次操作。

输出描述

按照输入顺序,对于每个1操作,输出一行一个整数表示对应的和。

示例1

输入:

7 5
1 1 1 1 1 1 1
1 2
1 3
2 4
2 5
3 6
3 7
2 3 1
3 1 1
1 2
1 3
1 6

输出:

4
7
2

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(clang++11) 解法, 执行用时: 1109ms, 内存消耗: 100216K, 提交时间: 2020-12-18 20:14:45

#include<iostream>
#include<vector>
using namespace std;
#define ll long long
struct madoka{
	ll l;
	ll r;
	ll sum;
	ll f;
}ma[2000007];
ll n,q,a[1000007],u,v,cnt,op,vis[1000007],pos[1000007],son[1000007];
ll res[1000007],fa[1000007];
vector<ll>ho[1000007];
void dfs(ll p,ll f){
	vis[p]=++cnt;
	pos[cnt]=p;
	fa[p]=f;
	for(int i=0;i<ho[p].size();i++){
		ll to=ho[p][i];
		if(to==f)continue;
		dfs(to,p);
	}
	son[p]=cnt;
}
void build(ll l,ll r,ll k){
	ma[k].l=l;
	ma[k].r=r;
	if(l==r){
		ma[k].sum=a[pos[l]];
		return;
	}
	ll mid=(l+r)/2;
	build(l,mid,k*2);
	build(mid+1,r,k*2+1);
	ma[k].sum=ma[k*2].sum+ma[k*2+1].sum;
	return;
}
void down(ll k){
	if(ma[k].f!=0&&ma[k].l!=ma[k].r){
		ma[k*2].f+=ma[k].f;
		ma[k*2+1].f+=ma[k].f;
		ma[k*2].sum+=(ma[k*2].r-ma[k*2].l+1)*ma[k].f;
		ma[k*2+1].sum+=(ma[k*2+1].r-ma[k*2+1].l+1)*ma[k].f;
		ma[k].f=0;
	}
}
void up(ll k,ll l,ll r,ll z){
	down(k);
	if(l<=ma[k].l&&ma[k].r<=r){
		ma[k].sum+=(ma[k].r-ma[k].l+1)*z;
		ma[k].f+=z;
		return;
	}
	ll mid=(ma[k].l+ma[k].r)/2;
	if(l<=mid){
		up(k*2,l,r,z);
	}
	if(mid<r){
		up(k*2+1,l,r,z);
	}
	ma[k].sum=ma[k*2].sum+ma[k*2+1].sum;
}
ll qry(ll k,ll l,ll r){
	down(k);
	if(l<=ma[k].l&&ma[k].r<=r){
		return ma[k].sum;
	}
	ll mid=(ma[k].l+ma[k].r)/2,ans=0;
	if(l<=mid){
		ans+=qry(k*2,l,r);
	}
	if(mid<r){
		ans+=qry(k*2+1,l,r);
	}
	return ans;
}
int main() {
	scanf("%lld%lld",&n,&q);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<n;i++){
		scanf("%lld%lld",&u,&v);
		ho[u].push_back(v);
		ho[v].push_back(u);
	}
	dfs(1,0);
	build(1,n,1);
	while(q--){
		scanf("%lld",&op);
		if(op==1){
			scanf("%lld",&u);
			printf("%lld\n",qry(1,vis[u],son[u])+res[fa[u]]);
		}
		else if(op==2){
			scanf("%lld%lld",&u,&v);
			up(1,vis[u],son[u],v);
		}
		else{
			scanf("%lld%lld",&u,&v);
			if(u==1)up(1,vis[u],vis[u],(ho[u].size()+1)*v);
			else up(1,vis[u],vis[u],ho[u].size()*v);
			res[u]+=v;
		}
	}
}

上一题