【树链剖分】[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;
}

posted on 2015-07-23 16:43  JeremyGuo  阅读(119)  评论(0编辑  收藏  举报

导航