001. P3038 [USACO11DEC] Grass Planting G
边转点 Trick,把每个边的边权下放到这个边上深度更为深的点上。因为每个点的父边唯一。然后在树剖的时候,\(u\) 到 \(v\) 路径上的深度最低的点直接不修改,因为深度最浅的点所对应的实际上并不是 \(u\) 到 \(v\) 路径上的边。然后就是正常树链剖分,这题是区间加,单点查,非常简单的板子。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MAXN = 100005;
LL n, m, Fa[MAXN], siz[MAXN], son[MAXN], depth[MAXN], top[MAXN], dfn[MAXN], dfsTime = 0;
vector<LL> Adj[MAXN];
void DFS1(LL u, LL fa)
{Fa[u] = fa; depth[u] = depth[fa] + 1; siz[u] = 1;for(LL i = 0; i < (LL)Adj[u].size(); i ++){LL v = Adj[u][i];if(v == fa) continue;DFS1(v, u);siz[u] += siz[v];if(siz[v] > siz[son[u]]) son[u] = v;}return;
}
void DFS2(LL u, LL Top)
{top[u] = Top; dfn[u] = ++ dfsTime; if(son[u]) DFS2(son[u], Top);for(LL i = 0; i < (LL)Adj[u].size(); i ++){LL v = Adj[u][i];if(v == Fa[u] || v == son[u]) continue;DFS2(v, v);}return;
}
struct Node
{LL L, R, sum, tag;
} Sgt[MAXN << 2];
void PushUp(LL o)
{Sgt[o].sum = Sgt[o << 1].sum + Sgt[o << 1 | 1].sum;return;
}
void PushDown(LL o)
{Sgt[o << 1].tag += Sgt[o].tag; Sgt[o << 1 | 1].tag += Sgt[o].tag;Sgt[o << 1].sum += Sgt[o].tag * (Sgt[o << 1].R - Sgt[o << 1].L + 1);Sgt[o << 1 | 1].sum += Sgt[o].tag * (Sgt[o << 1 | 1].R - Sgt[o << 1 | 1].L + 1);Sgt[o].tag = 0;return;
}
void BuildTree(LL o, LL L, LL R)
{if(L == R){Sgt[o] = Node{L, R, 0, 0};return;}LL mid = (L + R) >> 1;BuildTree(o << 1, L, mid); BuildTree(o << 1 | 1, mid + 1, R);PushUp(o);Sgt[o].L = Sgt[o << 1].L; Sgt[o].R = Sgt[o << 1 | 1].R;return;
}
void UpdateAdd(LL o, LL Ql, LL Qr)
{if(Ql <= Sgt[o].L && Sgt[o].R <= Qr){Sgt[o].tag ++; Sgt[o].sum += (Sgt[o].R - Sgt[o].L + 1);return;}PushDown(o);LL mid = (Sgt[o].L + Sgt[o].R) >> 1;if(Ql <= mid) UpdateAdd(o << 1, Ql, Qr);if(mid < Qr) UpdateAdd(o << 1 | 1, Ql, Qr);PushUp(o);return;
}
LL QuerySum(LL o, LL QPos)
{if(Sgt[o].L == Sgt[o].R) return Sgt[o].sum;PushDown(o);LL mid = (Sgt[o].L + Sgt[o].R) >> 1, ans = 0;if(QPos <= mid) ans += QuerySum(o << 1, QPos);else ans += QuerySum(o << 1 | 1, QPos);return ans;
}
void UpdatePath(LL u, LL v)
{while(top[u] != top[v]){if(depth[top[u]] < depth[top[v]]) swap(u, v);UpdateAdd(1, dfn[top[u]], dfn[u]);u = Fa[top[u]];}if(depth[v] < depth[u]) swap(u, v);if(u != v) UpdateAdd(1, dfn[u] + 1, dfn[v]);return;
}
int main()
{ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);cin >> n >> m;for(LL i = 1; i < n; i ++){LL u, v;cin >> u >> v;Adj[u].push_back(v); Adj[v].push_back(u);}DFS1(1, 0); DFS2(1, 1); BuildTree(1, 1, n);while(m --){char Opt;cin >> Opt;if(Opt == 'P'){LL u, v;cin >> u >> v;UpdatePath(u, v);}else{LL u, v;cin >> u >> v;if(depth[u] > depth[v]) cout << QuerySum(1, dfn[u]) << '\n';else cout << QuerySum(1, dfn[v]) << '\n';}}return 0;
}