Little Girl and Problem on Trees - CodeForces #169 (Div. 2) E 树状数组

Little Girl and Problem on Trees
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

A little girl loves problems on trees very much. Here's one of them.

A tree is an undirected connected graph, not containing cycles. The degree of node x in the tree is the number of nodes y of the tree, such that each of them is connected with node x by some edge of the tree.

Let's consider a tree that consists of n nodes. We'll consider the tree's nodes indexed from 1 to n. The cosidered tree has the following property: each node except for node number 1 has the degree of at most 2.

Initially, each node of the tree contains number 0. Your task is to quickly process the requests of two types:

  • Request of form: 0 v x d. In reply to the request you should add x to all numbers that are written in the nodes that are located at the distance of at most d from node v. The distance between two nodes is the number of edges on the shortest path between them.
  • Request of form: 1 v. In reply to the request you should print the current number that is written in node v.
Input

The first line contains integers n (2 ≤ n ≤ 105) and q (1 ≤ q ≤ 105) — the number of tree nodes and the number of requests, correspondingly.

Each of the next n  -  1 lines contains two integers ui and vi (1 ≤ ui, vi ≤ nui ≠ vi), that show that there is an edge between nodes uiand vi. Each edge's description occurs in the input exactly once. It is guaranteed that the given graph is a tree that has the property that is described in the statement.

Next q lines describe the requests.

  • The request to add has the following format: 0 v x d (1 ≤ v ≤ n1 ≤ x ≤ 1041 ≤ d < n).
  • The request to print the node value has the following format: 1 v (1 ≤ v ≤ n).

The numbers in the lines are separated by single spaces.

Output

For each request to print the node value print an integer — the reply to the request.

Sample test(s)
input
3 6
1 2
1 3
0 3 1 2
0 2 3 1
0 1 5 2
1 1
1 2
1 3
output
9
9
6
input
6 11
1 2
2 5
5 4
1 6
1 3
0 3 1 3
0 3 4 5
0 2 1 4
0 1 5 5
0 4 6 2
1 1
1 2
1 3
1 4
1 5
1 6
output
11
17
11
16
17
11


题意:一棵树有n个节点,但是除了根节点1外,其他节点都的出度和入度加起来就只有2(就是棵树是由几条链的第一个节点粘在一起的),现在有两种操作(1)"0 v x d",在距离v节点距离d以内的所有节点的权值都加上1,(2)"1 v",查询节点v上的权值。

思路:动态地开n个树状数组,然后每次记录这条枝上的更新,用vc[0]树状数组记录所有会更新到其他枝上的更新。

AC代码如下:

#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
vector<int> qu[100010];
vector<int>vc[100010];
map<int,ll> match;
ll MOD=1e6;
int num,vis[100010],L[100010],maxn,ans0;
int lowbit(int x)
{
    return x&(-x);
}
void update(int x,int pos,int val)
{
    //printf("update %d %d %d\n",x,pos,val);
    for(;x<=L[pos];x+=lowbit(x))
       vc[pos][x]+=val;
}
int query(int x,int pos)
{
    int ans=0;
    for(;x>0;x-=lowbit(x))
       ans+=vc[pos][x];
    return ans;
}
void dfs(int u,int d,int l)
{
    vc[d].push_back(0);
    vis[u]=1;
    match[u]=d*MOD+l;
    //printf("  ss %I64d\n",match[u]);
    if(qu[u].size()==1)
      return;
    for(int i=0;i<=1;i++)
       if(vis[qu[u][i]]==0)
         dfs(qu[u][i],d,l+1);
}
int main()
{
    int n,m,i,j,k,u,v,pos,l,len,val,l_1,r_1;
    scanf("%d%d",&n,&m);
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        qu[u].push_back(v);
        qu[v].push_back(u);
    }
    num=qu[1].size();
    //printf("num %d\n",num);
    vis[1]=1;
    for(i=1;i<=num;i++)
    {
        vc[i].push_back(0);
        dfs(qu[1][i-1],i,1);
    }
    maxn=0;
    for(i=1;i<=num;i++)
    {
        L[i]=vc[i].size()-1;
        maxn=max(maxn,L[i]);
    }
    //printf("maxn %d\n",maxn);
    L[0]=maxn;
    for(i=0;i<=maxn;i++)
       vc[0].push_back(0);
    while(m--)
    {
        scanf("%d",&k);
        if(k==1)
        {
            scanf("%d",&u);
            pos=match[u]/MOD;
            l=match[u]%MOD;
            //printf("  %d %d\n",pos,l);
            if(l==0)
              printf("%d\n",ans0);
            else
              printf("%d\n",query(l,pos)+query(l,0));
        }
        else
        {
            scanf("%d%d%d",&u,&val,&len);
            if(u==1)
            {
                ans0+=val;
                update(1,0,val);
                update(min(len,maxn)+1,0,-val);
                continue;
            }
            pos=match[u]/MOD;
            l=match[u]%MOD;
            r_1=min(l+len,L[pos]);
            l_1=max(l-len,1);
            update(l_1,pos,val);
            update(r_1+1,pos,-val);
            if(l-len<=0)
              ans0+=val;
            if(l-len<0)
            {
                update(1,0,val);
                update(len-l+1,0,-val);
                update(1,pos,-val);
                update(len-l+1,pos,val);
            }
        }
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值