Ka Chang 瀋陽網路賽 (樹上分塊+dfs序時間戳+樹狀陣列 )
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
題目來源
題意:有兩個操作,操作1是對於一個深度l上面的結點的權值增加v,操作2是對於一個結點求和它的子樹
題解:首先可以考慮可以維護一個樹狀陣列來維護子樹的權值和,但是若同一層結點太多那必然超時,則可以考慮分塊的思想來分開討論,對於同一深度設一個閾值limit,若這一深度中結點的個數>limit,則不實際進行更改,而是用一個數組來標記,因為>limit的層數不會太多,所以可以直接暴力列舉所有超越閾值的層數對於答案的貢獻,同時二分答案即可。在這裡遇到了一個我以前沒接觸到的一個知識點,如何判斷一個點是另一個點子樹中的點,一個新的知識點--DFS序+時間戳,記錄一個結點在dfs中第一次出現的時間和最後一次出現的時間若一個結點時間的區間是另一個結點時間區間的子區間(同時區間不可能相交),則這個點為另一個點子樹的子節點,根據這個性質就可以進行維護樹狀陣列了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
typedef long long ll;
vector<int>G[maxn],dep[maxn],large;
int st[maxn],ed[maxn],tim,n;
ll tree[maxn],num[maxn];
void add(int pos,ll v)
{
for(;pos<=n;pos+=pos&-pos)
tree[pos]+=v;
}
ll query(int pos)
{
ll ans=0;
for(;pos;pos-=pos&-pos)
ans+=tree[pos];
return ans;
}
void dfs(int u,int fa,int depth) //時間戳
{
st[u]=++tim;
dep[depth].push_back(tim);
int sz=G[u].size();
for(int i=0;i<sz;i++)
if(G[u][i]!=fa)
dfs(G[u][i],u,depth+1);
ed[u]=tim;
}
int main()
{
int q;
scanf("%d%d",&n,&q);
for(int i=0;i<n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0,0);
int block=ceil(sqrt(n));
for(int i=0;i<n;i++)
if(dep[i].size()>block)
large.push_back(i);
while(q--)
{
int nood;
scanf("%d",&nood);
if(nood==1)
{
int depth;
ll v;
scanf("%d%lld",&depth,&v);
if(dep[depth].size()>block) num[depth]+=v;
else
{
for(int i=0;i<dep[depth].size();i++)
add(dep[depth][i],v);
}
}
else
{
int x;
scanf("%d",&x);
ll ans=query(ed[x])-query(st[x]-1);
for(int i=0;i<large.size();i++)
ans+=(upper_bound(dep[large[i]].begin(),dep[large[i]].end(),ed[x])-lower_bound(dep[large[i]].begin(),dep[large[i]].end(),st[x]))*num[large[i]];
printf("%lld\n",ans);
}
}
}