CodeForces - 383C Propagating tree(dfs + 线段树)

题目大意:

给出一棵树,树上每个节点都有权值,然后有两个操作。

1 x val 在结点x上加上一个值val,x的儿子加上 -val,x的儿子的儿子加上 - (-val),以此类推。

2 x 问x节点的值。


思路分析:

每个节点上加值都是给自己的儿子节点加,而且这个是颗树。

比如样例上的,如果你给node 1加一个值,那么五个节点都加。

再给node 2加个值,2的儿子节点也加了,之前给1加的值也要加到2号节点的儿子。

所以你会发现节点的儿子会存在一个从属的关系。

这样的话,我们可以把所有节点从新编号。然后记录一下这个节点能更新哪个区间。然后就是简单的线段树了。

再说一下加法的合并。每一个操作都记录这个操作的节点的深度,然后合并的时候再考虑一下深度是如何合并的就好了。


#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define maxn 200005
#define maxm 1000005
#define lson num<<1,s,mid
#define rson num<<1|1,mid+1,e
using namespace std;

int tot;
int a[maxn];
int head[maxm],to[maxm],next[maxm];
int num[maxn],ed[maxn],dep[maxn],rev[maxn];
int res[maxn<<2];
int add[maxn<<2];
int cov[maxn<<2];

int Abs(int x)
{
    return x>0?x:-x;
}
void pushdown(int num,int s,int e)
{
    if(cov[num])
    {
        if(!cov[num<<1])cov[num<<1]=cov[num],add[num<<1]=add[num];
        else
        {
            if(Abs(cov[num<<1]-cov[num])&1)add[num<<1]+=-add[num];
            else add[num<<1]+=add[num];
        }

        if(!cov[num<<1|1])cov[num<<1|1]=cov[num],add[num<<1|1]=add[num];
        else
        {
            if(Abs(cov[num<<1|1]-cov[num])&1)add[num<<1|1]+=-add[num];
            else add[num<<1|1]+=add[num];
        }

        cov[num]=0,add[num]=0;
    }
}
void build(int num,int s,int e)
{
    cov[num]=0;
    add[num]=0;
    if(s==e)
    {
        res[num]=a[rev[s]];
        return;
    }
    int mid=(s+e)>>1;
    build(lson);
    build(rson);
}
void update(int num,int s,int e,int l,int r,int dp,int val)
{
    if(l<=s && r>=e)
    {
        if(!cov[num])
        {
            cov[num]=dp;
            add[num]=val;
        }
        else
        {
            if(Abs(cov[num]-dp)&1)add[num]+=-val;
            else add[num]+=val;
        }
        return;
    }
    int mid=(s+e)>>1;
    pushdown(num,s,e);
    if(l<=mid)update(lson,l,r,dp,val);
    if(r>mid)update(rson,l,r,dp,val);
}
int query(int num,int s,int e,int pos)
{
    if(s==e)
    {
        if(cov[num])
        {
            if(Abs(cov[num]-dep[s])&1)res[num]+=-add[num];
            else res[num]+=add[num];
            cov[num]=0,add[num]=0;
        }
        return res[num];
    }
    int mid=(s+e)>>1;
    pushdown(num,s,e);
    if(pos<=mid)return query(lson,pos);
    else return query(rson,pos);
}
void addedge(int u,int v)
{
    tot++;
    to[tot]=v;
    next[tot]=head[u];
    head[u]=tot;
}
int cnt=0;
bool vis[maxn];

int dfs(int x,int dp)
{
    num[x]=++cnt;
    dep[num[x]]=dp;
    int d=num[x];
    for(int p=head[x]; p; p=next[p])
    {
        if(vis[to[p]])continue;
        vis[to[p]]=true;
        d=max(d,dfs(to[p],dp+1));
    }
    ed[num[x]]=d;
    return ed[num[x]];
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++)
        scanf("%d",&a[i]);
    tot=0;
    memset(head,0,sizeof head);

    for(int i=1; i<n; i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
    }

    memset(vis,false,sizeof vis);
    vis[1]=true,dep[1]=1;
    dfs(1,1);
    for(int i=1; i<=cnt; i++)
    {
        rev[num[i]]=i;
    }
    build(1,1,cnt);
    while(m--)
    {
        int op;
        scanf("%d",&op);
        if(op==1)
        {
            int x,val;
            scanf("%d%d",&x,&val);
            if(num[x]>ed[num[x]])update(1,1,cnt,ed[num[x]],num[x],dep[num[x]],val);
            else update(1,1,cnt,num[x],ed[num[x]],dep[num[x]],val);
        }
        else
        {
            int x;
            scanf("%d",&x);
            printf("%d\n",query(1,1,cnt,num[x]));
        }
    }
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值