题意:
给你一颗n个节点的树,每一个节点的值为0。
q种操作,1.将深度为L的点的权值加x,根节点的深度为0
2.输出以x为根节点的子树的权值和
解析:
这道题最后想到了分块,因为我想到用的一种方法需要用[1e5][1e5]的空间去维护,有空间问题,
然后借此想到分块可以处理,小的部分暴力,大的部分用数组保存状态,这样就存的下了
不过我想的是按层来分块,前block层,和后block层,最后发现并没有什么用
搜了题解,是按照每一层内的点的个数来分类的,因为最暴力的做法,就是每一次修改,
把该层每一个点都更新一遍,所以我们就将每一层按照顶点数分块,
对于点>block的层称为重层,点<block的层称为轻层。
题解的这个分块方法主要不是解决空间的问题,而是通过block来解决时间的问题
对于轻层,因为点的个数<block,所以我们抓住这个,更新的时候用暴力更新,每一个点
对应树状数组更新一遍,时间O(block*logn),然后查询的时候,就用树状数组查询O(logn)
对于重层,重层的层的数量是n/block,我们抓住这个,更新的时候,就将更新的值保存在数组里O(1),
查询的时候再遍历每一层查询O(n/block*logn)
最后就是一些细节了,对于树状数组插入的时候,我们是按照每一个点的dfs序下标插入的,这样
我们查询x的子树时,我们只要知道x的dfs序和x的子树大小,就可以在树状数组中查到该子树内轻层
的点的权值和
然后对于重层,更新的时候只要存每一个重层更新的权值和,然后查询x的子树的时候,从x层遍历
在它下面的重层,对于每一个重层,依照dfs序进行两次二分,查出该层属于x的子数的点的个数inc
再*mark,就是答案了
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <vector>
#include <map>
using namespace std;
typedef long long ll;
const int MAXN = 1e5+10;
vector<int> edge[MAXN];
vector<int> dep[MAXN];
map<int,int> mdfs;
int sz[MAXN];
int md[MAXN];
ll c[MAXN];
ll mark[MAXN];
int n;
int maxdep,big[MAXN],cnt;
int lowbit(int x)
{
return x&(-x);
}
void add(int x,int y)
{
int i;
for(i=x;i<=n;i+=lowbit(i))
c[i]+=y;
}
ll sum(int x)
{
int i;
ll s=0;
for(i=x;i>0;i-=lowbit(i))
{
s+=c[i];
}
return s;
}
int dfs(int x,int d,int &ind)
{
maxdep=max(maxdep,d);
mdfs[x]=ind;
dep[d].push_back(ind);
md[x]=d;
sz[x]=1;
for(int i=0;i<edge[x].size();i++)
{
ind++;
sz[x]+=dfs(edge[x][i],d+1,ind);
}
return sz[x];
}
int main()
{
int q;
scanf("%d%d",&n,&q);
int block=sqrt(n);
int x,y;
maxdep=0;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
edge[x].push_back(y);
}
int ind=1;
dfs(1,1,ind);
cnt=0;
for(int i=1;i<=maxdep;i++)
{
if(dep[i].size()>block) big[cnt++]=i;
}
int id;
for(int i=0;i<q;i++)
{
scanf("%d",&y);
if(y==1)
{
scanf("%d%d",&x,&id);
x++;
if(dep[x].size()<=block)
{
for(int j=0;j<dep[x].size();j++)
add(dep[x][j],id);
}
else
{
mark[x]+=id;
}
}
else
{
scanf("%d",&x);
int nex=mdfs[x]+sz[x];
ll res=sum(nex-1)-sum(mdfs[x]-1);
int beg=lower_bound(big,big+cnt,md[x])-big;
for(int j=beg;j<cnt;j++)
{
int h=big[j];
int inc=upper_bound(dep[h].begin(),dep[h].end(),nex-1)-(lower_bound(dep[h].begin(),dep[h].end(),mdfs[x]));
res+=(inc)*mark[h];
}
printf("%lld\n",res);
}
}
return 0;
}