Ka Chang

Given a rooted tree ( the root is node 11 ) of NN nodes. Initially, each node has zero point.

Then, you need to handle QQ operations. There're two types:

1\ L\ X1 L X: Increase points by XX of all nodes whose depth equals LL ( the depth of the root is zero ). (x \leq 10^8)(x≤108)

2\ X2 X: Output sum of all points in the subtree whose root is XX.

Input

Just one case.

The first lines contain two integer, N,QN,Q. (N \leq 10^5, Q \leq 10^5)(N≤105,Q≤105).

The next n-1n−1 lines: Each line has two integer aa,bb, means that node aa is the father of node bb. It's guaranteed that the input data forms a rooted tree and node 11 is the root of it.

The next QQ lines are queries.

Output

For each query 22, you should output a number means answer.

样例输入复制

3 3
1 2
2 3
1 1 1
2 1
2 3

样例输出复制

1
0

题目来源

ACM-ICPC 2018 沈阳赛区网络预赛

给你一棵有根树,有两种操作,一是把某一层的所有的节点增加一个val,二是输出一个节点所在的子树的和。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lowbit(x)  x&(-x)
typedef pair<int,int>pa;
const int maxn=100050;
const int inv=5e8+4;
vector<int>g[maxn],dep[maxn],large;
int n,num,q,l[maxn],r[maxn];
ll s[maxn],c[maxn];
void dfs(int x,int fa,int depth)
{
    l[x]=++num;
    dep[depth].push_back(num);
    for(int i=0;i<g[x].size();i++)
    {
        int y=g[x][i];
        if(y==fa)
        {
            continue;
        }
        dfs(y,x,depth+1);
    }
    r[x]=num;
}
void update(int x,int y)
{
    for(int i=x;i<=n;i+=lowbit(i))
    {
        c[i]+=y;
    }
}
ll getsum(int x)
{
    ll res=0;
    for(int i=x;i;i-=lowbit(i))
    {
        res+=c[i];
    }
    return res;
}
int main()
{
    scanf("%d %d",&n,&q);
    int lim=ceil(sqrt(n));
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d %d",&x,&y);
        g[x].push_back(y);
        g[y].push_back(x);
    }
    dfs(1,0,0);
    for(int i=0;i<n;i++)
    {
        if(dep[i].size()>lim)
        {
            large.push_back(i);
        }
    }
    while(q--)
    {
        int op,x,y;
        scanf("%d",&op);
        scanf("%d",&x);
        if(op==1)
        {
            scanf("%d",&y);
            if(dep[x].size()>lim)
            {
                s[x]+=y;
            }
            else
            {
                for(int i=0;i<dep[x].size();i++)
                {
                    update(dep[x][i],y);
                }
            }
        }
        else
        {
            ll ans=getsum(r[x])-getsum(l[x]-1);
            for(int i=0;i<large.size();i++)
            {
                ans+=(upper_bound(dep[large[i]].begin(),dep[large[i]].end(),r[x])-lower_bound(dep[large[i]].begin(),dep[large[i]].end(),l[x]))*s[large[i]];
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值