1. 程式人生 > >noi2015 軟體包管理器 樹鏈剖分 + 線段樹維護

noi2015 軟體包管理器 樹鏈剖分 + 線段樹維護

題目意思:
給你n個節點,n-1條邊構造一棵樹,接著有兩種型別的詢問和操作:
1.求某個點到根的鏈上的所有值為0的點的總個數,然後將所有為0的節點改為為1的節點。
2.求某個點的子樹中的所有值為1的點的總個數,然後將所有值為1的節點改為為0的節點。

分析:
很簡單的樹剖思想:將所有的點按照dfs序編號後,利用一顆線段樹來維護樹剖則可以加速這個過程,使得整體時間複雜度降為

O(mlog2(n)log2(n))

程式碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000
+ 10; int read(int &n) { int f = 1; n = 0; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar(); } while(ch >='0' && ch <='9') { n = n * 10 + ch - 48; ch = getchar(); } n *= f; } struct SegmentTree { int n; int val[maxn * 4
], add[maxn * 4], sum[maxn * 4]; void init(int &n) { this -> n = n; memset(sum, 0, sizeof(sum)); memset(add, 0, sizeof(add)); memset(val, 0, sizeof(val)); } void Push_down(int u, int m) { if(add[u]) { int lc = u << 1, rc = u << 1
| 1; add[lc] = 1; val[lc] = val[u]; sum[lc] = (m - (m >> 1)) * val[u]; add[rc] = 1; val[rc] = val[u]; sum[rc] = (m >> 1) * val[u]; }add[u] = 0; } void Push_up(int u) { int lc = u << 1, rc = u << 1 | 1; sum[u] = sum[lc] + sum[rc]; } void update(int u, int l, int r, int sl, int sr, int v) { if(sl <= l && r <= sr) { add[u] = 1; val[u] = v; sum[u] = (r - l + 1) * v; return; } Push_down(u, (r - l + 1)); int lc = u << 1, rc = u << 1 | 1, mid = (l + r) >> 1; if(sl <= mid) update(lc, l, mid, sl, sr, v); if(sr > mid) update(rc, mid+1, r, sl, sr, v); Push_up(u); } int query(int u, int l, int r, int sl, int sr) { if(sl <= l && r <= sr) return sum[u]; Push_down(u, (r - l + 1)); int lc = u << 1, rc = u << 1 | 1, mid = (l + r) >> 1, tmp = 0; if(sl <= mid) tmp += query(lc, l, mid, sl, sr); if(sr > mid) tmp += query(rc, mid+1, r, sl, sr); return tmp; } }ST; int n, m, u, v, T; int Begin[maxn], Next[maxn*2], To[maxn*2], E; void Add(int x, int y) { To[++E] = y; Next[E] = Begin[x]; Begin[x] = E; } int tid[maxn], cnt; int dep[maxn], size[maxn], top[maxn], son[maxn], fa[maxn]; void dfs1(int cur, int f, int d) { dep[cur] = d; son[cur] = -1; size[cur] = 1; for(int i=Begin[cur]; i; i=Next[i]) { int t = To[i]; if(t != f) { dfs1(t, cur, d+1); fa[t] = cur; size[cur] += size[t]; if(son[cur] == -1 || size[t] > size[son[cur]]) son[cur] = t; } } } void dfs2(int cur, int tp) { top[cur] = tp; tid[cur] = ++cnt; if(son[cur] == -1) return; dfs2(son[cur], tp); for(int i=Begin[cur]; i; i=Next[i]) { int t = To[i]; if(t != fa[cur] && t != son[cur]) dfs2(t, t); } } void install(int x, int y) { int ans = ST.sum[1]; while(top[x] != top[y]) { if(dep[x] < dep[y]) swap(x, y); int l = tid[top[x]], r = tid[x]; ST.update(1, 1, cnt, l, r, 1); x = fa[top[x]]; } if(dep[x] < dep[y]) swap(x, y); int l = tid[y], r = tid[x]; ST.update(1, 1, cnt, l, r, 1); ans = ST.sum[1] - ans; printf("%d\n", ans); } void init() { E = cnt = 0; ST.init(n); memset(fa, 0, sizeof(fa)); memset(son, 0, sizeof(son)); memset(Begin, 0, sizeof(Begin)); for(int i=1; i<n; i++) { read(v), Add(v, i); }dfs1(0, -1, 0); dfs2(0, 0); } char st[30]; int main() { #ifndef ONLINE_JUDGE freopen("data.txt", "r", stdin); freopen("ans.txt", "w", stdout); #endif read(n); init(); read(m); while(m--) { scanf("%s%d", st, &u); if(st[0] == 'i') install(0, u); else { int ans = ST.sum[1]; ST.update(1, 1, cnt, tid[u], tid[u]+size[u]-1, 0); ans -= ST.sum[1]; printf("%d\n", ans); } } return 0; }