题解 P2146 【[NOI2015]软件包管理器】

题目大意

​ 给你一棵树, 求一点到根的路径上有多少个未标记点并全标记, 和询问一个点的子树内有多少已标记点和撤销标记


解题方法

1: install 操作

​ 这个操作是求一点到根的路径上有多少个未标记点并全标记, 这种操作可以用树链剖分来解决,将已标记的点的权值设为1, 求和即可

2.uninstall 操作

​ 这个操作询问一个点的子树内有多少已标记点和撤销标记, 同理上面的方法就好了。


代码实现

#include <bits/stdc++.h>
using namespace std;

template<class T>
inline void read(T &a){
    T s = 0, w = 1;
    char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') w = -1; c =getchar();}
    while(c >= '0' && c <= '9') {s = (s << 1) + (s << 3) + (c ^ 48); c = getchar();}
    a = s * w;
}
#define maxn 200100
#define maxm 200100

static int n, m;
static int net[maxm], to[maxm], head[maxm], tot;

inline void add(int x, int y){
    net[++tot] = head[x], head[x] = tot, to[tot] = y;
}


/*-----------------------------------------------------------*/

static int fat[maxn], size[maxn], deep[maxn];
static int son[maxn];
void dfs1(int x, int fa){
    fat[x] = fa;
    size[x] = 1;
    son[x] = 0;
    deep[x] = deep[fa] + 1;
    for (int i = head[x];i;i = net[i]){
        int v = to[i];
        if(v == fa) continue;
        dfs1(v, x);
        size[x] += size[v];
        if(size[v] > size[son[x]]) son[x] = v;
    }
}
static int tid[maxn], hhd[maxn], cnt, top[maxn];
void dfs2(int x, int t, int fa){
    tid[x] = ++cnt; hhd[cnt] = x; top[x] = t;
    if(!son[x]) return;
    top[x] = t;
    dfs2(son[x], t, x);
    for (int i = head[x];i;i = net[i]){
        int v = to[i];
        if(v == fa || v == son[x]) continue;
        dfs2(v, v, x);
    }
}
/*-----------------------------------------*/
static int Sum[maxn * 8], lazy[maxn * 8]; 
#define ls rt << 1
#define rs rt << 1 | 1
inline void push_down(int rt, int l, int r){
    int mid = (l + r) / 2;
    Sum[ls] = (mid - l + 1) * lazy[rt];
    Sum[rs] = (r -  (mid + 1)  + 1) * lazy[rt];
    lazy[ls] = lazy[rt]; lazy[rs] = lazy[rt];
    lazy[rt] = -1;
}


int ans = 0;
int Query(int rt, int l, int r, int L, int R){
    if(L <= l && r <= R){
        return Sum[rt];
    }
    else{
        int mid = (l + r) / 2;
        if(lazy[rt] != -1) push_down(rt, l, r);
        int ans = 0;
        if(L <= mid) ans += Query(ls, l, mid, L, R);
        if(R > mid) ans += Query(rs, mid + 1, r, L, R);
        Sum[rt] = Sum[ls] + Sum[rs];
        return ans;
    }
}

void Change(int rt, int l, int r, int L, int R, int d){
    if(L <= l && r <= R){
        Sum[rt] = (r - l + 1) * d;
        lazy[rt] = d;
    }
    else{
        int mid = (l + r) / 2;
        if(lazy[rt] != -1) push_down(rt, l, r);
        if(L <= mid) Change(ls, l , mid, L, R, d);
        if(R > mid) Change(rs, mid + 1, r, L, R, d);
        Sum[rt] = Sum[ls] + Sum[rs];
    }
}

inline int Query_path(int x, int y){
    int fx = top[x], fy = top[y];
    int ans = 0;
    while(fx != fy){
        if(deep[x] < deep[y]) swap(x, y), swap(fx, fy);
        ans += Query(1, 1, n, tid[fx], tid[x]);
        x = fat[fx];
        fx = top[x];
    }
    if(tid[x] < tid[y]) swap(x, y), swap(fx, fy);
    ans += Query(1, 1, n, tid[y], tid[x]);
    return ans;
}

inline void Change_path(int x, int y, int d){
    int fx = top[x], fy = top[y];
    int ans = 0;
    while(fx != fy){
        if(deep[x] < deep[y]) swap(x, y), swap(fx, fy);
        Change(1, 1, n, tid[fx], tid[x], d);
        x = fat[fx];
        fx = top[x];
    }
    if(tid[x] < tid[y]) swap(x, y);
    Change(1, 1, n, tid[y], tid[x], d);
}

int main(){
#ifndef ONLINE_JUDGE 
    freopen("p2146.in","r", stdin);
    freopen("p2146.out","w", stdout);
#endif
    memset(lazy, -1, sizeof(lazy));
    read(n); 
    for (int i = 1; i <= n-1; i++){
        int x;
        read(x);
        add(x + 1, i + 1); add(i + 1, x + 1);
    }
    read(m);
    dfs1(1, 0);
    dfs2(1,1,0);
//  build(1, 1, n);
    for (int i = 1; i <= m; i++){
        string s;
        cin>>s;
    //  cout<<s<<endl;
        if(s == "install"){
            int x;
            read(x); x++;
        //  printf("ss %d\n",i);
            int ans = Query_path(1, x);
            printf("%d\n", deep[x] - ans);
            Change_path(1, x, 1);
        }
        else{
            int x = 0;
            read(x); x++;
            int ans = Query(1, 1, n, tid[x], tid[x] + size[x] - 1);
            printf("%d\n", ans);
            Change(1, 1, n, tid[x], tid[x] + size[x] - 1, 0);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Ender-zzm/p/10577437.html