//题意:有一棵树,有两个指令 // 指令1:0 u delta,这棵树长出了一些果子, 即u的子树中的每个节点都会长出delta个果子 // 指令2:1 k u1 v1 ... uk vk,小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝 // 上的节点的果子数的和。注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次。 //思路:第一个指令很简单,直接dfs序区间操作就好 // 主要是第二个指令,充分发挥了树剖将路径操作转化为区间的性质 // 将路径转化许多区间之后,如果有路径重合,那么就是有区间重合,我们直接并区间就好 // (ps:本题的查询部分的树状数组懒得写了,只写到区间并的阶段) // #include<bits/stdc++.h> using namespace std; #define int long long const int N = 2e5 + 10; int tr[N]; int n, q; vector<int> mp[N]; int dep[N], siz[N], son[N], L[N], R[N], f[N], tot, top[N], idx[N]; void dfs(int x, int fa) { dep[x] = dep[fa] + 1; f[x] = fa; siz[x] = 1; for (auto y : mp[x]) { if (y == fa) continue; dfs(y, x); siz[x] += siz[y]; if (siz[son[x]] < siz[y]) son[x] = y; } }//重链剖分前置处理 void dfs1(int x, int w) { L[x] = ++tot; top[x] = w; idx[tot] = x; if (son[x]) dfs1(son[x], w); for (auto y : mp[x]) { if (y == f[x] || y == son[x]) continue; dfs1(y, y); } R[x] = tot; }//重链剖分,注意dfs序是这个时候的dfs序,因为之后要根据这个来更新线段树的(这道题用树状数组来整) void modify(int x, int s) { for (; x <= n; x += x & (-x)) tr[x] += s; } pair<int, int> edge[4 * N]; int cnt; void query(int u, int v) { while(top[u]!=top[v]){ if (dep[top[u]] < dep[top[v]]) { edge[++cnt] = { L[top[v]], L[v] }; v = f[top[v]]; } else { edge[++cnt] = { L[top[u]], L[u] }; u = f[top[u]]; } } if (dep[u] <= dep[v]) edge[++cnt] = { L[u],L[v] }; else edge[++cnt] = { L[v],L[u] }; } int way[4 * N][2]; int cnt1;//记录最终路径数 void merge() { sort(edge + 1, edge + 1 + cnt); way[0][0] = 0, way[0][1] = 0; for (int i = 1; i <= cnt; i++) { if (edge[i].first <= way[cnt1][1]) way[cnt1][1] = max(way[cnt1][1], edge[i].second); else if (edge[i].first > way[cnt1][1]) { way[++cnt1][0] = edge[i].first; way[cnt1][1] = edge[i].second; } } }//合并所有询问区间 int lookfor(int x) { int s = 0; for (; x; x -= x & (-x)) s += tr[x]; return s; } int query1() { int ans = 0; for (int i = 1; i <= cnt1; i++) { ans = ans - lookfor(way[i][0]); ans = ans + lookfor(way[i][1]); //cout << way[i][0] << " " << way[i][1] << endl; } return ans; } signed main() { cin >> n; for (int i = 1; i <= n - 1; i++) { int a, b; cin >> a >> b; mp[a].push_back(b); mp[b].push_back(a); } dep[0] = 0; dfs(1, 0); dfs1(1, 1); cin >> q; for (int i = 1; i <= q; i++) { int od, a, b, c; cin >> od; if (od == 0) { cin >> a >> b; //modify(R[a], b); //modify(L[a], -b); } else { cin >> c; for (int j = 1; j <= c; j++) { cin >> a >> b; query(a, b); } merge(); int ans = 0; ans = ans + query1(); //for (int i = 1; i <= cnt; i++) //cout << edge[i].first << " " << edge[i].second << endl; cout << ans << endl; } } return 0; }
标签:树剖,int,siz,top,dfs,son,dep,动态 From: https://www.cnblogs.com/Aacaod/p/17017941.html