一棵有N个节点的树,每个节点对应1个编号及1个权值,有2种不同的操作。
操作1:S x y z,表示如果编号为x的节点的权值 < y,则将节点x的权值加上z。(Single)
操作2:A x y z,表示如果编号为x的节点以及其所有子节点的权值平均值 < y,则将节点x及其所有子节点的权值加上z。(All)
给出树节点之间的关系,进行M次操作,问所有操作完成后,各个节点的权值为多少?
节点的编号为0 - N - 1,根节点的编号为0,并且初始情况下,根节点的权值也是0。
Input
第1行:2个数N, M,N为节点的数量,M为操作的数量(1 <= N, M <= 50000)。
第2 - N行:每行描述一个节点N[i]的信息,第2行对应编号为1的节点,第N行对应编号为N - 1的节点。具体内容为:每行2个数P[i], W[i]。P[i]为当前节点的父节点的编号,W[i]为当前节点的权值。(0 <= W[i] <= 10^5, P[i] < i)
第N + 1 - N + M行:每行表示一个操作,S x y z或A x y z,(0 <= y, z <= 10^5)。
Output
输出共N行,每行1个数W[i],表示经过M次后,编号为0 - N - 1的节点的权值。
Input示例
4 3
0 10
0 10
1 2
S 0 1 1
A 0 20 1
S 3 2 1
Output示例
2
11
11
3
思路:先跑一遍dfs序,求出每个节点的管辖区间,然后线段是维护即可
#include <bits/stdc++.h>
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
const double eps=1e-8;
const double Pi=acos(-1.0);
const int N= 50005;
struct T
{
ll val;
ll addmark;
} tree[N<<4];
struct node
{
int to;
ll val;
};
vector<node> G[N];
int L[N],R[N];
ll W[N];
int n,m,ti;
void addedge(int u,int v,ll w)
{
G[u].push_back((node){v,w});
G[v].push_back((node){u,w});
}
void init()
{
ti=0;
for(int i=0; i<=n; i++)
G[i].clear();
memset(L,0,sizeof(L));
memset(R,0,sizeof(R));
memset(W,0,sizeof(W));
memset(tree,0,sizeof(tree));
}
void dfs(int u,int w,int per)
{
L[u]=++ti;
W[ti]=w;
for(int i=0; i<(int)G[u].size(); i++)
{
int v=G[u][i].to;
int c=G[u][i].val;
if(v==per)
continue;
dfs(v,c,u);
}
R[u]=ti;
}
void build(int root,int l,int r)
{
if(l==r)
tree[root].val=W[l];
else
{
int mid=(l+r)>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
tree[root].val=tree[root<<1].val+tree[root<<1|1].val;
}
}
void push_down(int root,int l,int r)
{
if(tree[root].addmark!=0)
{
int mid=(l+r)>>1;
tree[root<<1].addmark+=tree[root].addmark;
tree[root<<1|1].addmark+=tree[root].addmark;
tree[root<<1].val+=tree[root].addmark*(mid-l+1);
tree[root<<1|1].val+=tree[root].addmark*(r-(mid+1)+1);
tree[root].addmark=0;
}
}
ll query(int root,int l,int r,int b,int e)
{
if(b>r||e<l)
return 0;
if(b<=l&&r<=e)
return tree[root].val;
push_down(root,l,r);
int mid=(l+r)>>1;
ll sum=0;
sum+=query(root<<1,l,mid,b,e);
sum+=query(root<<1|1,mid+1,r,b,e);
return sum;
}
void simple_updata(int root,int l,int r,int ind,ll add)
{
if(l==r)
{
tree[root].val+=add;
return ;
}
int mid=(l+r)>>1;
if(ind<=mid)
simple_updata(root<<1,l,mid,ind,add);
else
simple_updata(root<<1|1,mid+1,r,ind,add);
tree[root].val=tree[root<<1].val+tree[root<<1|1].val;
}
void interval_updata(int root,int l,int r,int b,int e,ll add)
{
if(b>r||e<l)
return ;
if(b<=l&&r<=e)
{
tree[root].addmark+=add;
tree[root].val+=add*(r-l+1);
return ;
}
push_down(root,l,r);
int mid=(l+r)>>1;
interval_updata(root<<1,l,mid,b,e,add);
interval_updata(root<<1|1,mid+1,r,b,e,add);
tree[root].val=tree[root<<1].val+tree[root<<1|1].val;
}
int main()
{
init();
scanf("%d %d",&n,&m);
int u;
ll w;
for(int i=1; i<n; i++)
{
scanf("%d %I64d",&u,&w);
addedge(u,i,w);
}
dfs(0,0,-1);
// for(int i=1;i<=n;i++)
// printf("%d\n",W[i]);
// for(int i=0;i<n;i++)
// printf("i:%d L:%d R:%d\n",i,L[i],R[i]);
build(1,1,n);
char ch; int x; ll y,z,num;
for(int i=0;i<m;i++)
{
getchar();
scanf("%c %d %I64d %I64d",&ch,&x,&y,&z);
if(ch=='S')
{
num=query(1,1,n,L[x],L[x]);
//printf("i:%d simple:%I64d\n",i+1,num);
if(num<y)
simple_updata(1,1,n,L[x],z);
}
else if(ch=='A')
{
num=query(1,1,n,L[x],R[x]);
//printf("i:%d interval:%I64d\n",i+1,num);
if((num/(R[x]-L[x]+1))<y)
interval_updata(1,1,n,L[x],R[x],z);
}
}
for(int i=0;i<n;i++)
printf("%I64d\n",query(1,1,n,L[i],L[i]));
}