版权声明:本文为博主原创文章,转载请著名出处 http://blog.csdn.net/u013534123 https://blog.csdn.net/u013534123/article/details/82556547
大致题意:给你一棵有根树,有两种操作,一是把某一层的所有的节点增加一个val,二是输出一个节点所在的子树的和。
普通的dfs序可以支持子树查询,但是不能支持按照深度的修改。对于一个深度,修改一次的复杂度是klogn,k为这个神的的节点个数,可以看出,如果是一个类似菊花图的东西,时间复杂度会爆炸。然后为了解决菊花图下的复杂度问题,我们考虑在修改的时候知识对某一个深度打上一个标记,然后在查询的时候,遍历对应子树的所有深度,用对应深度的点的个数乘以深度的改变量即可。但是这样在遇到链的情况下,同样复杂度退化。
于是我们考虑用分块来综合两种算法。对于同一个点比较多的深度,我们修改的时候对这个深度打上标记,而对于那些点的个数比较少的深度,我们则直接修改。按照套路,我们选取作为这个分界点,当点数大于时,对深度打标记,小于的时候直接暴力更新。下面分析一个这个的时间复杂度。对于修改操作,如果是大于的深度,代价是O(1)的;如果小于则暴力修改,最坏是)的,前面的是对应深度点的个数,后面是树状数组修改的代价。对于查询操作,首先计算那些点的个数小于的深度的和,这个直接用树状数组求子树区间的和即可,复杂度O(logn);然后是点的个数大于的深度的部分,我们枚举所有这些深度,对于深度i,我们用lowerbound和upperbound找到这个子树中深度为i的点的个数,乘上深度i的改变量累加到结果中即可,复杂度最坏也是,前一个表示点的个数大于的深度的个数,最多不会超过。
综上所述,总的时间复杂度就是的。分块算法很好的把解决两种极端问题的方法结合到了一起。具体见代码:
#include<bits/stdc++.h>
#define mod 1000000007
#define LL long long
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define INF 0x3f3f3f3f
#define sf(x) scanf("%d",&x)
#define sc(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define clr(x,n) memset(x,0,sizeof(x[0])*(n+5))
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
using namespace std;
const int N = 1e5 + 10;
const int inv = 5e8 +4;
std::vector<int> g[N],dep[N],large;
int n,num,q,l[N],r[N];
LL s[N],c[N];
void dfs(int x,int fa,int depth)
{
l[x]=++num;
dep[depth].pb(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+=i&-i)
c[i]+=y;
}
LL getsum(int x)
{
LL res=0;
for(int i=x;i;i-=i&-i)
res+=c[i];
return res;
}
int main()
{
sf(n); sf(q);
int lim=ceil(sqrt(n));
for(int i=1;i<n;i++)
{
int x,y;
sf(x); sf(y);
g[x].pb(y); g[y].pb(x);
}
dfs(1,0,0);
for(int i=0;i<n;i++)
if (dep[i].size()>lim) large.pb(i);
while(q--)
{
int op,x,y;
sf(op); sf(x);
if (op==1)
{
sf(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+=(ub(dep[large[i]].begin(),dep[large[i]].end(),r[x])-
lb(dep[large[i]].begin(),dep[large[i]].end(),l[x]))*s[large[i]];
printf("%lld\n",ans);
}
}
return 0;
}