P2146 [NOI2015] 软件包管理器 树链剖分

复制代码
//题目大意:给定一棵树,树上的每个节点是一个软件,现在给出如下两个指令,install与uninstall,
//          如果需要install x号软件,那么我需要安装他到根节点之间的所有软件;如果我需要卸载
//          uninstall所有的软件,那么我需要先卸载他子树中的所有软件。现在我们询问每次给定操作
//          对其他多少软件造成了影响
// 
// 思路:install很简单,直接处理该点到根节点之间的链即可
//       uninstall直接处理l[x]到r[x]这个子树区间就好,因为他们在dfs序中是连续的
//
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
vector<int> mp[N];
int n, m;
int l[N], r[N], idx[N];
int sz[N], hs[N], tot, top[N], dep[N], fa[N];
int read() {
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c>'9') { if (c == '-') f = -1; c = getchar(); }
    while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
void dfs1(int u, int f) {//第一遍dfs,求子树大小,重儿子,父亲,深度
    sz[u] = 1;
    hs[u] = -1;
    fa[u] = f;
    dep[u] = dep[f] + 1;
    for (auto v : mp[u]) {
        if (v == f) continue;
        dfs1(v, u);
        sz[u] += sz[v];
        if (hs[u] == -1 || sz[v] > sz[hs[u]])
            hs[u] = v;
    }
}
void dfs2(int u, int t) {//第二次dfs,求每个点的dfs序,重链上的链头元素
    top[u] = t;
    l[u] = ++tot;
    idx[tot] = u;
    if (hs[u] != -1) {
        dfs2(hs[u], t);
    }//优先遍历重链,如此一来将重链的dfs序搞成连续的
    for (auto v : mp[u]) {
        if (v != fa[u] && v != hs[u])
            dfs2(v, v);//这里很重要,最开始被dls坑了
    }
    r[u] = tot;
}
struct info {
    int st;//区间未安装
    int fst;//-1全卸载,0无标记,1全安装
}seg[4 * N];
void update(int id) {
    seg[id].st = seg[2 * id].st + seg[2 * id + 1].st;
}
void build(int id, int l, int r) {
    if (l == r) {
        //我们是对dfs序建树,所以这里要注意是dfs序中l号点
        seg[id].st = 1;
        seg[id].fst = 0;
    }
    else {
        int mid = (l + r) / 2;
        build(id * 2, l, mid);
        build(id * 2 + 1, mid + 1, r);
        update(id);
    }
}
void pushdown(int id, int l, int r) {
    if (seg[id].fst == 0) return;
    int mid = (l + r) / 2;
    if (seg[id].fst == 1) {
        seg[id * 2].st = (mid - l + 1);
        seg[id * 2 + 1].st = (r - mid);
        seg[id * 2].fst = seg[2 * id + 1].fst = 1;
        seg[id].fst = 0;
    }
    else {
        seg[id * 2].st = 0;//全部变为安装
        seg[id * 2 + 1].st = 0;
        seg[id * 2].fst = seg[2 * id + 1].fst = -1;
        seg[id].fst = 0;
    }
}
int query1(int id, int l, int r, int ql, int qr) {
    if (ql == l && qr == r) {
        return seg[id].st;
    }
    pushdown(id, l, r);
    int mid = (l + r) / 2;
    if (qr <= mid) return query1(id * 2, l, mid, ql, qr);
    else if (ql > mid) return query1(id * 2 + 1, mid + 1, r, ql, qr);
    else {
        return query1(id * 2, l, mid, ql, mid) + query1(id * 2 + 1, mid + 1, r, mid + 1, qr);
    }
}
int query2(int id, int l, int r, int ql, int qr) {
    if (ql == l && qr == r) {
        return (r - l + 1) - seg[id].st;//已经被安装的软件数目
    }
    pushdown(id, l, r);
    int mid = (l + r) / 2;
    if (qr <= mid) return query2(id * 2, l, mid, ql, qr);
    else if (ql > mid) return query2(id * 2 + 1, mid + 1, r, ql, qr);
    else {
        return query2(id * 2, l, mid, ql, mid) + query2(id * 2 + 1, mid + 1, r, mid + 1, qr);
    }
}
void modify(int id, int l, int r, int ql, int qr, int od) {
    if (ql == l && qr == r) {
        if (od == -1) {
            seg[id].st = 0; seg[id].fst = -1;
            return;
        }
        else {
            seg[id].st = (r - l + 1); seg[id].fst = 1;
            return;
        }
    }
    pushdown(id, l, r);
    int mid = (l + r) / 2;
    if (qr <= mid) modify(2 * id, l, mid, ql, qr, od);
    else if (ql > mid) modify(2 * id + 1, mid + 1, r, ql, qr, od);
    else {
        modify(id * 2, l, mid, ql, mid, od); 
        modify(id * 2 + 1, mid + 1, r, mid + 1, qr, od);
    }
    update(id);
}
int query(int x, int od) {
    int ans = 0;
    if (od == 1) {
        while (top[x] != 1) {
            ans += query1(1, 1, n, l[top[x]], l[x]);//查询未安装数量
            modify(1, 1, n, l[top[x]], l[x], -1);//将所有都安装
            x = fa[top[x]];
        }
        ans += query1(1, 1, n, l[top[x]], l[x]);
        modify(1, 1, n, l[top[x]], l[x], -1);
    }
    else {
        ans += query2(1, 1, n, l[x], r[x]);
        modify(1, 1, n, l[x], r[x], 1);//将所有都卸载
    }
    return ans;
}
int main() {
    n = read();
    for (int i = 2; i <= n; i++) {
        int a; cin >> a;
        mp[a + 1].push_back(i);
        mp[i].push_back(a + 1);
    }
    dfs1(1, 0);
    dfs2(1, 1);
    build(1, 1, n);
    m = read();
    for (int i = 1; i <= m; i++) {
        string s; int od;
        cin >> s >> od; od++;
        if (s == "install") {
            //如果是安装的话,只用统计该点开始到根的未安装软件多少即可
            cout << query(od, 1) << endl;
        }
        else {
            //如果是要卸载的话,统计子树中已安装的软件,并且将dfs序区间全部清0即可
            cout << query(od, -1) << endl;
        }
    }
    return 0;
}
复制代码

 

posted @   Aacaod  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示