Codeforces 1076 E. Vasya and a Tree(dfs)

题目链接
题目大意:
给定一棵树,总共有m个操作,每个操作包括 v d k。
表示以v为根,在v的子树中所有深度 ≤ \le d+dep(v深度为dep)的节点权值都+k,最后输出每个顶点的权值。

解题思路:
对树进行dfs可以记录节点深度,每到一个节点,就把以当前节点为根的操作都进行一遍,例如当前深度为dep,就将Add[dep…dep+d]都+k,然后记录当前点的答案,但是dfs回溯的时候要将这些操作撤销,因为会变成处理另一棵子树了,就是将这些操作都变成-k重新操作一次就行了。对区间加减可以使用线段树或区间差分实现就行了。(代码中注释的是线段树操作,没注释的是区间差分,cin会T)。

解题代码:

#include<bits/stdc++.h>
using namespace std;
mt19937 rng_32(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
const ll maxn=3e5+10;
struct E{
    ll to,nxt;
}e[maxn*2];
ll tot,head[maxn];
ll Add[maxn<<2],lz[maxn<<2];
void adde(ll u,ll v)
{
    tot++;
    e[tot]={v,head[u]};
    head[u]=tot;
}
// void pushdown(ll x)
// {
//    if (lz[x])
//    {
//        Add[x<<1]+=lz[x];
//        Add[x<<1|1]+=lz[x];
//        lz[x<<1]+=lz[x];
//        lz[x<<1|1]+=lz[x];
//        lz[x]=0;
//    }
// }
// void update(ll l,ll r,ll i,ll ql,ll qr,ll add)
// {
//    if (ql<=l && qr>=r)
//    {
//        Add[i]+=add;
//        lz[i]+=add;
//        return ;
//    }
//    pushdown(i);
//    ll mid=(l+r)>>1;
//    if (ql<=mid)
//    update(l,mid,i<<1,ql,qr,add);
//    if (qr>mid)
//    update(mid+1,r,i<<1|1,ql,qr,add);
//    return ;
// }
// ll query(ll l,ll r,ll i,ll pos)
// {
//    if (l==r)
//    {
//        return Add[i];
//    }
//    pushdown(i);
//    ll mid=(l+r)>>1;
//    if (pos<=mid)
//    return query(l,mid,i<<1,pos);
//    else
//    return query(mid+1,r,i<<1|1,pos);   
// }
vector<pair<ll,ll> >v[maxn]; 
ll n;
ll ans[maxn];
void dfs(int u,int fa,int dep)
{
    int len=v[u].size();
    for (int i=0;i<len;i++)
    {
       int d=min(n+1,dep+v[u][i].first+1);
       Add[dep]+=v[u][i].second;
       Add[d]-=v[u][i].second;
    //    update(1,n,1,dep,min(n,dep+v[u][i].first),v[u][i].second);
    }
    Add[dep]+=Add[dep-1];
    ans[u]=Add[dep];
    //ans[u]=query(1,n,1,dep);
    for (int i=head[u];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if (to==fa)
        continue;
        dfs(to,u,dep+1);
    }
    for (int i=0;i<len;i++)
    {
        int d=min(n+1,dep+v[u][i].first+1);
        Add[dep]-=v[u][i].second;
        Add[d]+=v[u][i].second;
    //   update(1,n,1,dep,min(n,dep+v[u][i].first),-1ll*v[u][i].second);
    }
    Add[dep]-=Add[dep-1];
}
int main()
{
    cin>>n;   
    ll t1,t2;
    for (ll i=1;i<n;i++)
    {
    	scanf("%lld%lld",&t1,&t2);
        adde(t1,t2);
        adde(t2,t1);
    }
    ll m,t3;
    cin>>m;
    for (ll i=1;i<=m;i++)
    {
    	scanf("%lld%lld%lld",&t1,&t2,&t3);
        v[t1].push_back(make_pair(t2,t3));
    }
    dfs(1,1,1);
    for (int i=1;i<=n;i++)
    printf("%lld ",ans[i]);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值