//题目大意:给定一棵树,树上的每个节点是一个软件,现在给出如下两个指令,install与uninstall, // 如果需要install x号软件,那么我需要安装他到根节点之间的所有软件;如果我需要卸载 // uninstall所有的软件,那么我需要先卸载他子树中的所有软件。现在我们询问每次给定操作 // 对其他多少软件造成了影响 // // 思路:install很简单,直接处理该点到根节点之间的链即可 // uninstall直接处理l[x]到r[x]这个子树区间就好,因为他们在dfs序中是连续的 // #include<bits/stdc++.h> using namespace std; const int N = 1e5 + 10; vector<int> mp[N]; int n, m; int l[N], r[N], idx[N]; int sz[N], hs[N], tot, top[N], dep[N], fa[N]; int read() { int x = 0, f = 1; char c = getchar(); while (c < '0' || c>'9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } void dfs1(int u, int f) {//第一遍dfs,求子树大小,重儿子,父亲,深度 sz[u] = 1; hs[u] = -1; fa[u] = f; dep[u] = dep[f] + 1; for (auto v : mp[u]) { if (v == f) continue; dfs1(v, u); sz[u] += sz[v]; if (hs[u] == -1 || sz[v] > sz[hs[u]]) hs[u] = v; } } void dfs2(int u, int t) {//第二次dfs,求每个点的dfs序,重链上的链头元素 top[u] = t; l[u] = ++tot; idx[tot] = u; if (hs[u] != -1) { dfs2(hs[u], t); }//优先遍历重链,如此一来将重链的dfs序搞成连续的 for (auto v : mp[u]) { if (v != fa[u] && v != hs[u]) dfs2(v, v);//这里很重要,最开始被dls坑了 } r[u] = tot; } struct info { int st;//区间未安装 int fst;//-1全卸载,0无标记,1全安装 }seg[4 * N]; void update(int id) { seg[id].st = seg[2 * id].st + seg[2 * id + 1].st; } void build(int id, int l, int r) { if (l == r) { //我们是对dfs序建树,所以这里要注意是dfs序中l号点 seg[id].st = 1; seg[id].fst = 0; } else { int mid = (l + r) / 2; build(id * 2, l, mid); build(id * 2 + 1, mid + 1, r); update(id); } } void pushdown(int id, int l, int r) { if (seg[id].fst == 0) return; int mid = (l + r) / 2; if (seg[id].fst == 1) { seg[id * 2].st = (mid - l + 1); seg[id * 2 + 1].st = (r - mid); seg[id * 2].fst = seg[2 * id + 1].fst = 1; seg[id].fst = 0; } else { seg[id * 2].st = 0;//全部变为安装 seg[id * 2 + 1].st = 0; seg[id * 2].fst = seg[2 * id + 1].fst = -1; seg[id].fst = 0; } } int query1(int id, int l, int r, int ql, int qr) { if (ql == l && qr == r) { return seg[id].st; } pushdown(id, l, r); int mid = (l + r) / 2; if (qr <= mid) return query1(id * 2, l, mid, ql, qr); else if (ql > mid) return query1(id * 2 + 1, mid + 1, r, ql, qr); else { return query1(id * 2, l, mid, ql, mid) + query1(id * 2 + 1, mid + 1, r, mid + 1, qr); } } int query2(int id, int l, int r, int ql, int qr) { if (ql == l && qr == r) { return (r - l + 1) - seg[id].st;//已经被安装的软件数目 } pushdown(id, l, r); int mid = (l + r) / 2; if (qr <= mid) return query2(id * 2, l, mid, ql, qr); else if (ql > mid) return query2(id * 2 + 1, mid + 1, r, ql, qr); else { return query2(id * 2, l, mid, ql, mid) + query2(id * 2 + 1, mid + 1, r, mid + 1, qr); } } void modify(int id, int l, int r, int ql, int qr, int od) { if (ql == l && qr == r) { if (od == -1) { seg[id].st = 0; seg[id].fst = -1; return; } else { seg[id].st = (r - l + 1); seg[id].fst = 1; return; } } pushdown(id, l, r); int mid = (l + r) / 2; if (qr <= mid) modify(2 * id, l, mid, ql, qr, od); else if (ql > mid) modify(2 * id + 1, mid + 1, r, ql, qr, od); else { modify(id * 2, l, mid, ql, mid, od); modify(id * 2 + 1, mid + 1, r, mid + 1, qr, od); } update(id); } int query(int x, int od) { int ans = 0; if (od == 1) { while (top[x] != 1) { ans += query1(1, 1, n, l[top[x]], l[x]);//查询未安装数量 modify(1, 1, n, l[top[x]], l[x], -1);//将所有都安装 x = fa[top[x]]; } ans += query1(1, 1, n, l[top[x]], l[x]); modify(1, 1, n, l[top[x]], l[x], -1); } else { ans += query2(1, 1, n, l[x], r[x]); modify(1, 1, n, l[x], r[x], 1);//将所有都卸载 } return ans; } int main() { n = read(); for (int i = 2; i <= n; i++) { int a; cin >> a; mp[a + 1].push_back(i); mp[i].push_back(a + 1); } dfs1(1, 0); dfs2(1, 1); build(1, 1, n); m = read(); for (int i = 1; i <= m; i++) { string s; int od; cin >> s >> od; od++; if (s == "install") { //如果是安装的话,只用统计该点开始到根的未安装软件多少即可 cout << query(od, 1) << endl; } else { //如果是要卸载的话,统计子树中已安装的软件,并且将dfs序区间全部清0即可 cout << query(od, -1) << endl; } } return 0; }
标签:P2146,qr,管理器,剖分,int,mid,st,seg,id From: https://www.cnblogs.com/Aacaod/p/17016037.html