2025 atcoder 406
https://atcoder.jp/contests/abc406/tasks/abc406_f
点击查看代码
###**dfs序概念**
DFS序是指 对一棵树进行一次深度优先搜索(DFS)时,按照访问顺序给节点编号 得到的序列。它有两种常见形式:
####**1. 进入-退出序(欧拉序 / Euler Tour)**
每个节点在进入和退出时各记录一次,常用于 **子树查询、路径拆分**。
进入时间戳:in[u],第一次访问 u 时记录。
退出时间戳:out[u],回溯离开 u 时记录。
**性质:**
子树 u 的所有节点在 [in[u], out[u]] 区间内。
区间长度 = out[u] - in[u] + 1。
深度优先遍历的序列是 欧拉序,每个节点出现两次。
####**2. 纯 DFS 序(仅记录进入)**
只记录第一次访问节点的顺序,常用于 线性化树结构
* DFS序 = 把树拍扁成数组。
* 子树 = 连续区间(in[u] 到 out[u])。
* 路径 = 若干区间(树链剖分)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define lowbit(x) (x&(-x))
const int mxn = 3e5+5, md = 998244353;
int n, u[mxn], v[mxn], cnt;
int d[mxn]; //d[i] i点的深度
int dfn[mxn]; //时间戳
int sz[mxn]; //sz[i] i子树的节点数
int tree[mxn]; //树状数组
vector<int> e[mxn];
void dfs(int u, int fa){
d[u] = d[fa] + 1;
dfn[u] = ++cnt;
sz[u] = 1;
for(auto it : e[u]){
if(it == fa) continue;
dfs(it, u);
sz[u] += sz[it];
}
}
void modify(int u, int x){ //单点修改
for(int i = u; i <= n; i += lowbit(i)){
tree[i] += x;
}
}
int query(int u){ //区间查询
int ans = 0;
for(int i = u; i; i -= lowbit(i)){
ans += tree[i];
}
return ans;
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i < n; ++i){
cin >> u[i] >> v[i];
e[u[i]].push_back(v[i]);
e[v[i]].push_back(u[i]);
}
dfs(1, 0);
for(int i = 1; i <= n; ++i){
modify(i, 1); //初始时每个节点的权值为1
}
int q;
cin >> q;
while(q--){
int ch, x;
cin >> ch >> x;
if(ch == 1){
int w;
cin >> w;
modify(dfn[x], w);
}else{
int p = d[u[x]] > d[v[x]] ? u[x] : v[x]; //选深度大的点
int sum1 = query(dfn[p] + sz[p] - 1) - query(dfn[p] - 1);
int sum2 = query(n) - sum1;
// cout << query(dfn[p] + sz[p] - 1) << ' ' << query(dfn[p] - 1) << '\n';
cout << abs(sum1 - sum2) << '\n';
}
}
return 0;
}

浙公网安备 33010602011771号