首页 > 其他分享 >P2146 [NOI2015] 软件包管理器 树链剖分

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

时间:2022-12-30 23:23:32浏览次数:49  
标签:P2146 qr 管理器 剖分 int mid st seg id

//题目大意:给定一棵树,树上的每个节点是一个软件,现在给出如下两个指令,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;
}

 

标签:P2146,qr,管理器,剖分,int,mid,st,seg,id
From: https://www.cnblogs.com/Aacaod/p/17016037.html

相关文章

  • ZJOI2008, 树的统计 树链剖分模板
    //题意:给定一棵树,现在我需要询问以下操作//1.q,u之间的最小值//2.q,u之间的简单路径的权值和//3.修改树上q点的权值//思路:如果是在一段序列上的问......
  • Python学习二:Python包管理器pip
    文章目录​​前言​​​​一、pip是什么​​​​二、pip基本操作​​​​三、更改pip下载源为国内镜像​​​​四、操作安装的位置​​​​1.指定安装位置​​前言一、pip......
  • 处理手法学习(树链剖分)
    今天vp了两场cf,感觉对开眼界还是很有用的,手感也回来了点首先给出一些点,如何找出是否属于同一条链首先暴力方法就是每次dfs,在分叉大于2的地方看看是否包含所有的点这是个......
  • make工程管理器
    工程管理器,顾名思义,是指管理较多的文件Make工程管理器也就是个“自动编译管理器”,这里的“自动”是指它能构根据文件时间戳自动发现更新过的文件而减少编译的工作量,同时,它......
  • BZOJ 3252 攻略(长链剖分模板 链的常用性质 贪心)
    BZOJ3252攻略​ 给定一棵带边权的树,选择k个叶子结点,使这些叶子结点与根节点相连,形成k条路径。输出被路径覆盖的所有边的边权和的最大值(同一条边若被重复覆盖只算一......
  • eclipse资源管理器直接打开文件目录方法
    eclipse资源管理器直接打开文件目录方法:运行→外部工具→外部工具配置→程序(点击左上角有个文本+号的图标)→在名称输入“资源管理器”位置输入“C:\Windows\explorer.exe”......
  • 【实用快捷键】设置WebStorm中Show in Explorer(在资源管理器中打开)快捷键Alt+Shift+R(
    ......
  • Linux之资源管理器
    top命令用于实时的监控系统的处理器状态,以及其他硬件负载信息还有其他动态的进程信息等还可以按照排名,先后的显示某个进程CPU,内存的使用情况排名。top实际用法如下:1.进......
  • 包管理器
    包管理器用于对库的管理,包括安装、移除和依赖处理等。对于包管理器,可以考虑支持以下功能:安装库包括下载、编译(如有必要)、安装和移除。可以指定多个安装位置;可以设置......
  • 最大面积最小的三角剖分 Minimax Triangulation
    #include<iostream>#include<algorithm>#include<cmath>#include<vector>usingnamespacestd;#definemistake(P)(fabs(P)<eps?0:(P<0?-1:1))......