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,一共有两种操作。
操作1:将深度为L的这一层的节点都加上一个数X。
操作2:求X节点的所有子树上的节点值的和。
思路:
参考的博客:传送门
因为每次操作1是把一层都更新了,如果考虑操作1用一个数组记录下来所有层增加量,那么操作2的时间复杂度会很大。如果考虑操作2用dfs序+树状数组,那么操作1的更新的时间复杂度也很大。所以采用了分块的思想,将节点数大于等于sqrt(n)的那层直接用一个数组记录下来,这部分的操作2用二分出X的子树的每层大于sqrt(n)的节点数乘以它的变化值。而对于节点数小于sqrt(n)的一层则用暴力的修改在树状数组中的值,操作2用dfs序+树状数组来解决。这样折中了两者的复杂度。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
vector<int> e[maxn];
vector<int> d[maxn];
vector<int> que;
int n,m;
int in[maxn],out[maxn];
int ma;
ll a[maxn];
ll tr[maxn];
inline int lowbit(int i)
{
return i&(-i);
}
void add(int x,ll c)
{
while(x<=n){
tr[x]+=c;
x+=lowbit(x);
}
}
ll query(int x)
{
ll ans=0;
while(x){
ans+=tr[x];
x-=lowbit(x);
}
return ans;
}
int tot;
void dfs(int u,int fa,int deep)
{
in[u]=++tot;
d[deep].push_back(tot);
ma=max(deep,ma);
for(int i=0;i<e[u].size();i++){
int son=e[u][i];
if(son==fa) continue;
dfs(son,u,deep+1);
}
out[u]=tot;
}
int main()
{
int u,v,op,l,pos;
ll x;
scanf("%d%d",&n,&m);
for(int i=1;i<=n-1;i++){
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
int siz=sqrt(n);
dfs(1,-1,0);
for(int i=0;i<=ma;i++){
if(d[i].size()>=siz){
que.push_back(i);
}
}
for(int i=1;i<=m;i++){
scanf("%d",&op);
if(op&1){
scanf("%d%lld",&l,&x);
if(d[l].size()>=siz){
a[l]+=x;
}
else {
for(int i=0;i<d[l].size();i++){
add(d[l][i],x);
}
}
}
else {
scanf("%d",&pos);
ll ans=query(out[pos])-query(in[pos]-1);//小的值
for(int i=0;i<que.size();i++){
int deep=que[i];
ans+=a[deep]*((upper_bound(d[deep].begin(),d[deep].end(),out[pos]))-(lower_bound(d[deep].begin(),d[deep].end(),in[pos])));
}
printf("%lld\n",ans);
}
}
return 0;
}