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
题目来源
题意:一颗树,没个节点的值一开始都为0,现在有2种操作,第一种第L层每个节点的值增加x,第二种查询x为根的子树的权值和。
思路:dfs序+树状数组或者线段树是很快可以想到的,问题在于如果直接单点更新那么每次更新操作都是O(nlogn)的复杂度查询O(logn),又如果每次都是把每层增加的权值记录下来,查询的时候再找出这个子树中每个层的节点数量,那么每次更新复杂度O(1)查询复杂度是O(nlogn)的,所以把两者结合起来,对于节点数>sqrt(n)的层记录,反之直接单点更新。如此分块的话,每次的查询和查询复杂度都为O(sqrt(n)logn)。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<math.h>
#include<algorithm>
using namespace std;
const int maxn = 1e5+10;
typedef long long ll;
int n,q;
int cnt = 0;
int dfn[maxn]; //dfs序
int idc[maxn]; //每个节点在dfs序中的位置
int mp[maxn];
int rmp[maxn];
ll add[maxn]; //记录重层的增加量
int maxl;
vector<int>vec[maxn];
vector<int>level[maxn]; //每层的节点
vector<int>leveldfn[maxn]; //每层节点对应的的方式序
struct node
{
int sta,end;
}subtr[maxn];
void dfs(int x,int lvl)
{
dfn[++cnt] = x;
maxl = max(maxl,lvl);
level[lvl].push_back(x);
leveldfn[lvl].push_back(cnt);
idc[x] = cnt;
subtr[x].sta = cnt;
for(int i =0;i<vec[x].size();i++)
{
dfs(vec[x][i],lvl+1);
}
subtr[x].end = cnt;
}
ll c[maxn];
int Lowbit(int x)
{
return x&(-x);
}
void update(int i, ll x)
{
while(i <= n)
{
c[i] += x;
i += Lowbit(i);
}
}
ll sum(int x)
{
ll sum=0;
while(x>0)
{
sum+=c[x];
x-=Lowbit(x);
}
return sum;
}
ll Getsum(int x1,int x2)
{
return sum(x2) - sum(x1-1);
}
int main()
{
maxl = 0;
cnt = 0;
scanf("%d%d",&n,&q);
for(int i = 0;i<=n;i++)
{
vec[i].clear();
level[i].clear();
leveldfn[i].clear();
}
memset(add,0,sizeof(add));
memset(c,0,sizeof(c));
int u,v;
for(int i = 0;i<n-1;i++)
{
scanf("%d%d",&u,&v);
vec[u].push_back(v);
}
dfs(1,0);
int sqrtn = sqrt(n);
int addcnt = 0;
for(int i = 0;i<=maxl;i++)
{
if(level[i].size()>sqrtn)
{
mp[i] = addcnt;
rmp[addcnt++] = i;
}
}
int opt;
while(q--)
{
scanf("%d",&opt);
if(opt==1)
{
int L;
ll x;
scanf("%d%lld",&L,&x);
if(level[L].size()<=sqrtn)
{
for(int i = 0;i<level[L].size();i++)
{
update(idc[level[L][i]],x);
}
}
else
{
add[mp[L]] += x;
}
}
else
{
int x;
scanf("%d",&x);
ll ans = Getsum(subtr[x].sta,subtr[x].end);
int L;
for(int i = 0;i<addcnt;i++)
{
L = rmp[i];
int l = lower_bound(leveldfn[L].begin(),leveldfn[L].end(),subtr[x].sta) - leveldfn[L].begin();
int r = upper_bound(leveldfn[L].begin(),leveldfn[L].end(),subtr[x].end) - leveldfn[L].begin();
ans += (r - l)*add[i];
}
printf("%lld\n",ans);
}
}
}