【树链剖分】[BZOJ 4196]软件包管理器
实际上就是个树链剖分,每次询问自己需要的到根节点中有多少开/开了,然后根据需要输出然后线段树Update的时候改一下改成每次更新全部,直接覆盖就行,每次扫描出来的一段肯定是上面半段开下面半段不开(分成两段)或者全部都处于开或者关,因为在链上任意一个处于开启状态那么之前的必须也处于开始状态。就是这样。
#include <cstdio>
#include <algorithm>
#include <cstring>
//#include <conio.h>
#include <iostream>
using namespace std;
const int MAXN = 100000;
typedef long long LL;
LL add[MAXN<<2], sum[MAXN<<2];
int heavyson[MAXN+10], sons[MAXN+10], id[MAXN+10], last[MAXN+10], top[MAXN+10], idcnt;
int depend[MAXN+10], fid[MAXN+10], n;
struct node{
int v;
node *next;
}Edges[MAXN*2+10], *ecnt=Edges, *adj[MAXN+10];
void addedge(int u, int v){
++ecnt;
ecnt->v = v;
ecnt->next = adj[u];
adj[u] = ecnt;
}
void PushUp(int rt){sum[rt] = sum[rt<<1] + sum[rt<<1|1];}
void PushDown(int rt,int m){
if (add[rt] != 0) {
add[rt<<1] = add[rt<<1|1] = add[rt];
if(add[rt] == -1) add[rt] = 0;
sum[rt<<1] = add[rt] * (m - (m >> 1));
sum[rt<<1|1] = add[rt] * (m >> 1);
add[rt] = 0;
}
}
void update(int L,int R,int c,int l,int r,int rt) {
if (L <= l && r <= R) {
add[rt] = c;
sum[rt] = (c==-1?0:1) * (r - l + 1);
return ;
}
PushDown(rt , r - l + 1);
int mid = (l + r) >> 1;
if (L <= mid) update(L , R , c , l, mid, rt << 1);
if (mid < R) update(L , R , c , mid+1, r, (rt<<1)|1);
PushUp(rt);
}
LL query(int L,int R,int l,int r,int rt) {
if (L <= l && r <= R){
return sum[rt];
}
PushDown(rt , r - l + 1);
int mid = (l + r) >> 1;
LL ret = 0;
if (L <= mid) ret += query(L , R , l, mid, rt<<1);
if (mid < R) ret += query(L , R , mid+1, r, (rt<<1)|1);
return ret;
}
void dfs(int u){
sons[u] = 1; heavyson[u] = -1;
for(node *p=adj[u];p;p=p->next){
dfs(p->v);
sons[u] += sons[p->v];
if(heavyson[u] == -1 || sons[p->v] > sons[heavyson[u]])
heavyson[u] = p->v;
}
}
void dfs2(int u, int tp){
id[u] = ++idcnt; fid[idcnt] = u;
if(tp == -1) tp = top[u] = idcnt;
else top[u] = tp;
if(heavyson[u] > 0) dfs2(heavyson[u], tp);
for(node *p=adj[u];p;p=p->next) if(p->v != heavyson[u]){
dfs2(p->v, -1);
}
last[u] = idcnt;
}
int query_on(int u){
int tp = top[u], ret = 0, counter=0;
while(true){
counter += id[u]-tp+1;
if(tp == 1){
ret += query(1, id[u], 1, idcnt, 1);
update(top[u], id[u], 1, 1, idcnt, 1);
return counter - ret;
}
ret += query(top[u], id[u], 1, idcnt, 1);
update(top[u], id[u], 1, 1, idcnt, 1);
u = depend[fid[tp]]; tp = top[u];
}
return -1;
}
int query_off(int u){
int ret = query(id[u], last[u], 1, idcnt, 1);
update(id[u], last[u], -1, 1, idcnt, 1);
return ret;
}
char s[70];
int main() {
//printf("%.3lf\n", (1.0 * sizeof(heavyson) + sizeof(sons) + sizeof(id) + sizeof(fid) + sizeof (top) + sizeof(Edges) + sizeof(depend) + sizeof(add) + sizeof(sum) )/1024.0/1024.0);
//getch();
scanf("%d", &n);
for(int i=1;i<n;i++){
scanf("%d", &depend[i]);
addedge(depend[i], i);
}
dfs(0);
dfs2(0,-1);
int q, i_s;
scanf("%d", &q);
for(int i=0;i<q;i++){
scanf("%s%d", s, &i_s);
if(s[0] == 'u') printf("%d\n", query_off(i_s));
else printf("%d\n", query_on(i_s));
}
return 0;
}