F - Compare Tree Weights 解説 by en_translator
Regard the tree rooted at vertex \(1\).
Consider assigning to each vertex an integer \(f(v)\) in the pre-order of a DFS (Depth-First Search) starting from vertex \(1\). Then for all vertex \(v\) we have:
The integers assigned to the vertices in the subtree rooted at vertex \(v\) form a consecutive interval. In other words, there exists an integer pair \((l,r)\) with \(1\leq l\leq r\leq N\) such that a vertex is assigned an integer between \(l\) and \(r\) if and only if the vertex belongs to the subtree.
For \(v=1\), it clearly holds because the subtree is \(T\) itself. Otherwise, consider the visiting order in the DFS. Starting from vertex \(1\), you travel from the parent of vertex \(v\) to vertex \(v\) at some point, visit all descendants (including \(v\) itself), and go back to the parent, never visiting \(v\) (and its descendants) again.
By managing the vertex weights in an array \(A=(A_1,A_2,\ldots,A_N)\) indexed by the assigned integers, the query can be rephrased as follows:
1 x w
: increase \(A_{f(x)}\) by \(x\).2 y
: let \(v\) be the child vertex of edge \(y\). For the interval of indices corresponding to the subtree rooted at \(v\), find \(\left\lvert\left(\displaystyle\sum_{i=1}^{l-1}A_i+\displaystyle\sum_{i=r+1}^{N}A_i\right)-\displaystyle\sum_{i=l}^{r}A_i\right\rvert =\left\lvert\displaystyle\sum_{i=1}^{N}A_i-2\displaystyle\sum_{i=l}^{r}A_i\right\rvert\).
Sine we can update the total vertex weights \(\displaystyle\sum_{i=1}^{N}A_i\) per query, it is sufficient to perform element-wise additions and segment-sum retrieval fast. Using a data structure like Fenwick Tree, they can be done in \(O(\log N)\) time per query.
The interval corresponding to the subtree rooted at each vertex can be found in one DFS for all vertex: \(l\) is the integer assigned to that vertex, and \(r\) is the next integer to be assigned when returning from that vertex to its parent.
Therefore, the initial DFS costs \(O(N)\) and each query costs \(O(\log N)\), for a total time complexity of \(O(N+Q\log N)\), which is fast enough.
Thus the problem has been solved.
Sample code in C++:
#include <bits/stdc++.h>
#include <atcoder/fenwicktree>
using namespace std;
using namespace atcoder;
#define N 300010
int cur=0;
int l_idx[N];
int r_idx[N];
vector<int>e[N];
void dfs(int k){
l_idx[k]=cur;
cur++;
int sz=e[k].size();
for(int i=0;i<sz;i++)if(l_idx[e[k][i]]==-1)dfs(e[k][i]);
r_idx[k]=cur;
return;
}
int main() {
int n;
int u[N];
int v[N];
cin>>n;
for(int i=0;i<n-1;i++){
cin>>u[i]>>v[i];
u[i]--,v[i]--;
e[u[i]].push_back(v[i]);
e[v[i]].push_back(u[i]);
}
for(int i=0;i<n;i++)l_idx[i]=-1,r_idx[i]=-1;
dfs(0);
int q;
int t,x,w,y,z;
fenwick_tree<int> fw(n);
for(int i=0;i<n;i++)fw.add(i,1);
int s=n;
cin>>q;
for(int i=0;i<q;i++){
cin>>t>>x;
x--;
if(t==1){
cin>>w;
fw.add(l_idx[x],w);
s+=w;
}
else{
if(l_idx[u[x]]<l_idx[v[x]])y=v[x];
else y=u[x];
cout << abs(fw.sum(l_idx[y],r_idx[y])*2-s) <<endl;
}
}
return 0;
}
投稿日時:
最終更新: