http://codeforces.com/gym/100589/problem/A
线段树dfs序 根据每一层有多少节点来分块 还是对分块理解不到位 比赛就没想到。。
分块就是把要维护的数据结构按某种方法分成几个部分 来给操作的复杂度开根号
对于这道题 按最暴力的法子搞 有两种
一 对于更新操作 不管节点数量 直接暴力单点更o(num*logn) 那么查询就会很轻松 直接区间查询o(logn)
二 对于查询操作 不管节点数量 全部都存到数组来记录该层总体更新了多少 每次都是o(1) 但查询就很难受 要把所有大于等于根节点深度的层都算一遍 o(dep*logn) 具体就是每一层存一下该层上节点的dfs序 每次二分找一下左右边界
以上两种虽然都不可取 但两者都有各自的优点 法一的查询和法二的更新 这两者的复杂度恒定的优秀
主要是法一的更新和法二的查询 当该层节点数量很少时 法一的更新可以接受 反之复杂度感人 而法二的查询复杂度貌似总是无法接受
这时就要分情况处理 即按层的节点数量对层分类 设界限为N=sqrtn 会发现节点数超限的层数不超过n/N 即最多sqrtn
对于更新操作 节点数量少则法一 多则法二
对于查询操作 先看线段树维护的数量未超限的层数的权值和 o(logn) 再暴力扫一遍所有超限层即可 o(sqrtn*logn)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1000;
struct node
{
int v;
int next;
};
vector <int> pre1[100010],pre2[100010];
node edge[200010];
ll sum1[400010],sum2[100010];
int first[100010],deep[100010],mp[100010],tot[100010],tmp[100010];
int n,q,num;
void addedge(int u,int v)
{
edge[num].v=v;
edge[num].next=first[u];
first[u]=num++;
}
void dfs(int cur,int fa)
{
int i,v;
mp[cur]=++num,tot[cur]=1;
for(i=first[cur];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(v!=fa)
{
deep[v]=deep[cur]+1;
dfs(v,cur);
tot[cur]+=tot[v];
}
}
}
void pushup(int cur)
{
sum1[cur]=sum1[2*cur]+sum1[2*cur+1];
}
void update(int tar,ll val,int l,int r,int cur)
{
int m;
if(l==r)
{
sum1[cur]+=val;
return;
}
m=(l+r)/2;
if(tar<=m) update(tar,val,l,m,2*cur);
else update(tar,val,m+1,r,2*cur+1);
pushup(cur);
}
ll query(int pl,int pr,int l,int r,int cur)
{
ll res;
int m;
if(pl<=l&&r<=pr) return sum1[cur];
res=0,m=(l+r)/2;
if(pl<=m) res+=query(pl,pr,l,m,2*cur);
if(pr>m) res+=query(pl,pr,m+1,r,2*cur+1);
return res;
}
int main()
{
ll val,ans,len;
int i,tp,u,v,d;
scanf("%d%d",&n,&q);
memset(first,-1,sizeof(first));
num=0;
for(i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
deep[1]=1;
num=0;
dfs(1,0);
for(i=1;i<=n;i++)
{
pre1[deep[i]].push_back(i);
pre2[deep[i]].push_back(mp[i]);
}
for(i=1;i<=n;i++) sort(pre2[i].begin(),pre2[i].end());
num=0;
for(i=1;i<=n;i++) if(pre1[i].size()>N) tmp[num++]=i;
while(q--)
{
scanf("%d",&tp);
if(tp==1)
{
scanf("%d%lld",&d,&val);
d++;
if(pre1[d].size()>N) sum2[d]+=val;
else for(i=0;i<pre1[d].size();i++) update(mp[pre1[d][i]],val,1,n,1);
}
else
{
scanf("%d",&u);
ans=query(mp[u],mp[u]+tot[u]-1,1,n,1);
for(i=0;i<num;i++)
{
len=upper_bound(pre2[tmp[i]].begin(),pre2[tmp[i]].end(),mp[u]+tot[u]-1)-lower_bound(pre2[tmp[i]].begin(),pre2[tmp[i]].end(),mp[u]);
ans+=len*sum2[tmp[i]];
}
printf("%lld\n",ans);
}
}
return 0;
}