noi2015 軟體包管理器 樹鏈剖分 + 線段樹維護
阿新 • • 發佈:2019-02-06
題目意思:
給你n個節點,n-1條邊構造一棵樹,接著有兩種型別的詢問和操作:
1.求某個點到根的鏈上的所有值為0的點的總個數,然後將所有為0的節點改為為1的節點。
2.求某個點的子樹中的所有值為1的點的總個數,然後將所有值為1的節點改為為0的節點。
分析:
很簡單的樹剖思想:將所有的點按照dfs序編號後,利用一顆線段樹來維護樹剖則可以加速這個過程,使得整體時間複雜度降為
程式碼:
#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;
}