当前位置: 代码迷 >> 综合 >> 【Educational Codeforces Round 54 (Rated for Div. 2) E. Vasya and a Tree】 dfs+树状数组
  详细解决方案

【Educational Codeforces Round 54 (Rated for Div. 2) E. Vasya and a Tree】 dfs+树状数组

热度:0   发布时间:2023-12-29 02:31:16.0

E. Vasya and a Tree

题意

给你一颗n个点的树,每个点的权值最初为0给你一颗n个点的树,每个点的权值最初为0n0
有m个操作,每次操作有三个变量v,d,x有m个操作,每次操作有三个变量v,d,xmv,d,x
操作为在v的距离v&lt;=d的子树内所有节点权值+x操作为在v的距离v&lt;=d的子树内所有节点权值+xvv<=d+x
最终统计树上每个点的权值最终统计树上每个点的权值

做法

首先要明确两件事情首先要明确两件事情
性质1.每个人的操作只会影响到他的子孙(包括自己)性质1.每个人的操作只会影响到他的子孙(包括自己)1.()
性质2.每个人只会被他祖先的操作所影响(包括自己)性质2.每个人只会被他祖先的操作所影响(包括自己)2.()
也就是说,如果我们能在访问到某个节点时,统计出所有影响到该节点的祖先操作也就是说,如果我们能在访问到某个节点时,统计出所有影响到该节点的祖先操作访
就可以统计出这个节点的最终权值就可以统计出这个节点的最终权值
而对于每个操作,我们只要用一个dep数组保存每个深度被增加的值而对于每个操作,我们只要用一个dep数组保存每个深度被增加的值dep
所有深度大于当前节点的操作都会影响到当前节点,如果用线段树就是一个区间求和问题所有深度大于当前节点的操作都会影响到当前节点,如果用线段树就是一个区间求和问题线
为了减少代码量我们用树状数组,更新时只在本次操作的最深的深度更新为了减少代码量我们用树状数组,更新时只在本次操作的最深的深度更新
这样求一个1?maxdep的前缀和就是所有更新了根节点的操作这样求一个1-maxdep的前缀和就是所有更新了根节点的操作1?maxdep
在求一个1?(nowdep?1)的前缀和就是所有不包含当前节点的操作在求一个1-(nowdep-1)的前缀和就是所有不包含当前节点的操作1?(nowdep?1)
两个前缀和相减就是当前节点被更新的值两个前缀和相减就是当前节点被更新的值
为了保证每个操作只影响自己子树内的节点,在dfs退出子树时为了保证每个操作只影响自己子树内的节点,在dfs退出子树时dfs退
要将当前根节点的所有修改值还原要将当前根节点的所有修改值还原

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 3e5+10;
int n,m;
ll tree[maxn],ans[maxn];
vector<int> G[maxn],D[maxn],X[maxn];
void add(int x,int val)
{
    while(x<=n){
    tree[x]+=val;x=x+(x&-x);}
}
ll sum(int x)
{
    ll ans=0;while(x){
    ans+=tree[x];x=x-(x&-x);}return ans;
}
void dfs(int x,int fa,int dep)
{
    for(int i=0;i<D[x].size();i++){
    add(min(D[x][i]+dep,n),X[x][i]);//进子树之前更新}ans[x]=sum(n)-sum(dep-1);//树状数组变区间查询为两个前缀和相减//由于性质2,所以在这个地方就可以直接算出当前节点的最终答案for(int i=0;i<G[x].size();i++){
    if(G[x][i]==fa) continue;dfs(G[x][i],x,dep+1);}for(int i=0;i<D[x].size();i++){
    add(min(D[x][i]+dep,n),-X[x][i]);//出子树之后还原}
}
int main()
{
    int x,y,z;scanf("%d",&n);for(int i=1;i<=n-1;i++){
    scanf("%d%d",&x,&y);G[x].push_back(y);G[y].push_back(x);}scanf("%d",&m);for(int i=1;i<=m;i++){
    scanf("%d%d%d",&x,&y,&z);D[x].push_back(y);X[x].push_back(z);}dfs(1,0,1);for(int i=1;i<=n;i++){
    printf("%lld ",ans[i]);}return 0;
}
  相关解决方案