CodeForces 276E - Little Girl and Problem on Trees 区间更新..N+1个线段树

    注意题目设定..除了根节点1外...其他的点至多两个度..而每个非点必须要有一个父亲..所以每个非根节点至多一个孩子..说明题目所给的树一定是这样的:


   对于一个点的上下范围更新...有两种情况发生...一个是在所在的线段内更新...一个是上界超过了线段...更新到其他的线段上去...

   对于N个线段..可以用N个线段树来维护其区间更新...但是对于跨过1点更新到其他线段的情况..若每次一条一条的更新..绝对超市..这是用一颗特殊的线段树来维护从1出发到多深..加了多少的值...

   为了能方便的维护这颗特别的线段树...当其他的线段会更新到点1时...要做更新范围的调整..比如:


  要在2号点更新距离为3的..那么更新范围是红色标出的部分...把这个部分分解为为黄色和红色的部分分别处理..红色就是在这个线段是做区间更新..黄色是在点1记录的距离上区间更新... 

  由于N+1颗线段树的长度是未知的..所以用vector来开...因为vector是动态申请空间的..并且可以通过下标直接访问元素...


Program:

#include<iostream>
#include<stack>
#include<queue>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<cmath>
#define ll long long
#define oo 1000000007
#define MAXN 100004
using namespace std;  
struct node
{
       int Tn,g; 
}P[MAXN];
vector<int> T[MAXN],col[MAXN],t0;  
int n,num,M[MAXN];
void dfs(int x,int m,int f,int t)
{
      P[x].Tn=m,P[x].g=t;
      col[num].push_back(0);
      for (int i=0;i<T[x].size();i++)
        if (T[x][i]!=f) 
          dfs(T[x][i],m,x,t+1);
      if (t>M[0]) M[0]=t;
      return;
}
void PushDown(int M,int len,int now)
{
      if (!col[M][now]) return; 
      col[M][now<<1]+=col[M][now];
      col[M][(now<<1)|1]+=col[M][now]; 
      col[M][now]=0;
      return;
}
void update(int M,int L,int R,int c,int l,int r,int now) // M用于确定是哪颗树
{
      if (L<=l && R>=r)
      { 
              col[M][now]+=c;
              return;
      }
      PushDown(M,r-l+1,now);
      int mid=(l+r)>>1;
      if (L<=mid) update(M,L,R,c,l,mid,now<<1);
      if (R>mid)  update(M,L,R,c,mid+1,r,(now<<1)|1);
      return;      
}
int query(int M,int p,int l,int r,int now)   
{
      if (l==r) return col[M][now];
      PushDown(M,r-l+1,now);
      int mid=(l+r)>>1;
      if (p<=mid) return query(M,p,l,mid,now<<1);
      if (p>mid)  return query(M,p,mid+1,r,(now<<1)|1); 
}
int main()
{  
      int i,q; 
      scanf("%d%d",&n,&q);
      for (i=1;i<=n;i++) T[i].clear();
      for (i=1;i<n;i++)
      {
            int x,y;
            scanf("%d%d",&x,&y);
            T[x].push_back(y),T[y].push_back(x);
      }
      num=0,P[1].g=0,M[0]=0;
      for (i=0;i<T[1].size();i++)
      { 
            col[++num].clear(),col[num].push_back(0);
            dfs(T[1][i],num,1,1); 
      } 
      col[0].clear(); i=M[0]<<2;
      while (i--) col[0].push_back(0);
      for (i=1;i<=num;i++)
      {
            int x=col[i].size();
            M[i]=x-1,x<<=2;
            col[i].clear(); 
            while (x--) col[i].push_back(0);
      }
      while (q--)
      {
            int tp,v,x,d;
            scanf("%d",&tp);
            if (!tp)
            {
                    int l,r,p,t;
                    scanf("%d%d%d",&v,&x,&d);
                    if (P[v].g-d<=0) l=d-P[v].g+1,update(0,0,min(M[0],l-1),x,0,M[0],1);
                        else l=P[v].g-d;
                    if (v==1) continue;
                    r=min(M[P[v].Tn],P[v].g+d);
                    if (r<l) continue;
                    update(P[v].Tn,l,r,x,1,M[P[v].Tn],1); 
            }else
            {
                    int ans=0;
                    scanf("%d",&v); 
                    ans=query(0,P[v].g,0,M[0],1);
                    if (v!=1) ans+=query(P[v].Tn,P[v].g,1,M[P[v].Tn],1);
                    printf("%d\n",ans);
            }
      }
      return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值