zoukankan      html  css  js  c++  java
  • 【NOI 2015】软件包管理器

    【问题描述】

    Linux 用户和 OS X 用户一定对软件包管理器不会陌生。通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安装所依赖的其它软件包),完成所有的配置。Debian/Ubuntu 使用的 apt-get,Fedora/CentOS 使用的 yum,以及 OS X 下可用的 homebrew 都是优秀的软件包管理器。

    你决定设计你自己的软件包管理器。不可避免地,你要解决软件包之间的依赖问题。如果软件包 A 依赖软件包 B ,那么安装软件包 A 以前,必须先安装软件包 B 。同时,如果想要卸载软件包 B ,则必须卸载软件包 A 。现在你已经获得了所有的软件包之间的依赖关系。而且,由于你之前的工作,除 0 号软件包以外,在你的管理器当中的软件包都会依赖一个且仅一个软件包,而 0 号软件包不依赖任何一个软件包。依赖关系不存在环(若有 m(m ≥ 2) 个软件包 A1, A2, A3, ⋯, Am,其中 A1 依赖 A2, A2 依赖 A3, A3 依赖 A4, ⋯, Am−1 依赖 Am, 而 Am 依赖 A1, 则称这 m 个软件包的依赖关系构成环),当然也不会有一个软件包依赖自己。

    现在你要为你的软件包管理器写一个依赖解决程序。根据反馈,用户希望在安装和卸载某个软件包时,快速地知道这个操作实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包),你的任务就是实现这个部分。注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为 0。

    【输入格式】

    输入的第 1 行包含 1 个整数 n(n<=100000) ,表示软件包的总数。软件包从 0 开始编号。

    随后一行包含 n − 1 个整数,相邻整数之间用单个空格隔开,分别表示 1, 2, 3, ⋯ , n − 2, n − 1 号软件包依赖的软件包的编号。

    接下来一行包含 1 个整数 q(q<=100000),表示询问的总数。

    之后 q 行,每行 1 个询问。询问分为两种:

    1、install x:表示安装软件包 x

    2、uninstall x:表示卸载软件包 x

    你需要维护每个软件包的安装状态,一开始所有的软件包都处于未安装状态。

    对于每个操作,你需要输出这步操作会改变多少个软件包的安装状态,随后应用这个操作(即改变你维护的安装状态)。

    【输出格式】

    输出包括 q 行,第 i 行输出 1 个整数,为第 i 步操作中改变安装状态的软件包数。

    分析:

    总结题目实际上就是要求支持树上路径修改、查询,子树修改、查询,用树链剖分就可以支持树上路径修改、查询。

    因为树链剖分的编号也是一种dfs序,所以它也可以支持子树的修改、查询。

    代码:

      1 #include <cstdio>
      2 
      3 int n, q, u;
      4 char str[15];
      5 
      6 namespace S
      7 {
      8     int sum[500000], set[500000];
      9     int left[500000], right[500000];
     10 
     11     void build(int i, int l, int r)
     12     {
     13         sum[i] = 0;
     14         set[i] = -1;
     15         left[i] = l;
     16         right[i] = r;
     17         if (l < r)
     18         {
     19             build(i << 1, l, (l + r >> 1));
     20             build(i << 1 | 1, (l + r >> 1) + 1, r);
     21         }
     22     }
     23 
     24     void pushdown(int i)
     25     {
     26         if (set[i] == -1) return;
     27         int child = i << 1;
     28         set[child] = set[i];
     29         sum[child] = (right[child] - left[child] + 1) * set[i];
     30         child = i << 1 | 1;
     31         set[child] = set[i];
     32         sum[child] = (right[child] - left[child] + 1) * set[i];
     33         set[i] = -1;
     34     }
     35 
     36     void modify(int i, int l, int r, int k)
     37     {
     38         if (l <= left[i] && r >= right[i])
     39         {
     40             set[i] = k;
     41             sum[i] = (right[i] - left[i] + 1) * k;
     42             return;
     43         }
     44         pushdown(i);
     45         int mid = left[i] + right[i] >> 1;
     46         if (l <= mid) modify(i << 1, l, r, k);
     47         if (r > mid) modify(i << 1 | 1, l, r, k);
     48         sum[i] = sum[i << 1] + sum[i << 1 | 1];
     49     }
     50 
     51     int query(int i, int l, int r)
     52     {
     53         if (l <= left[i] && r >= right[i])
     54         {
     55             return sum[i];
     56         }
     57         pushdown(i);
     58         int ret = 0, mid = left[i] + right[i] >> 1;
     59         if (l <= mid) ret += query(i << 1, l, r);
     60         if (r > mid) ret += query(i << 1 | 1, l, r);
     61         return ret;
     62     }
     63 }
     64 
     65 namespace T
     66 {
     67     int et[100010], ep[100010], last[100010], en;
     68     int fa[100010], dep[100010], siz[100010];
     69     int son[100010], pos[100010], end[100010], top[100010], tot;
     70 
     71     void insert(int f, int t)
     72     {
     73         en++; et[en] = t; ep[en] = last[f]; last[f] = en;
     74     }
     75 
     76     void dfs(int x)
     77     {
     78         dep[x] = dep[fa[x]] + 1;
     79         siz[x] = 1;
     80         son[x] = 0;
     81         for (int i = last[x]; i; i = ep[i])
     82         {
     83             fa[et[i]] = x;
     84             dfs(et[i]);
     85             siz[x] += siz[et[i]];
     86             if (siz[et[i]] > siz[son[x]] || son[x] == 0)
     87                 son[x] = et[i];
     88         }
     89     }
     90 
     91     void dfs2(int x)
     92     {
     93         pos[x] = ++tot;
     94         if (son[x] > 0)
     95         {
     96             top[son[x]] = top[x];
     97             dfs2(son[x]);
     98             for (int i = last[x]; i; i = ep[i])
     99             {
    100                 if (et[i] != son[x])
    101                 {
    102                     top[et[i]] = et[i];
    103                     dfs2(et[i]);
    104                 }
    105             }
    106         }
    107         end[x] = tot;
    108     }
    109 
    110     int install(int x)
    111     {
    112         int ret = 0, t;
    113         if (S::query(1, pos[x], pos[x])) return 0;
    114         while (1)
    115         {
    116             t = top[x];
    117             ret += pos[x] - pos[t] + 1 - S::query(1, pos[t], pos[x]);
    118             S::modify(1, pos[t], pos[x], 1);
    119             x = fa[t];
    120             if (t == 0) break;
    121         }
    122         return ret;
    123     }
    124 
    125     int uninstall(int x)
    126     {
    127         if (S::query(1, pos[x], pos[x]) == 0) return 0;
    128         int ret = S::query(1, pos[x], end[x]);
    129         S::modify(1, pos[x], end[x], 0);
    130         return ret;
    131     }
    132 }
    133 
    134 int main()
    135 {
    136     scanf("%d", &n);
    137     for (int i = 1; i < n; i++)
    138     {
    139         scanf("%d", &u);
    140         T::insert(u, i);
    141     }
    142     T::dfs(0);
    143     T::dfs2(0);
    144     S::build(1, 1, T::tot);
    145     scanf("%d", &q);
    146     for (int i = 0; i < q; i++)
    147     {
    148         scanf("%s %d", str, &u);
    149         printf("%d
    ", (str[0] == 'u' ? T::uninstall(u) : T::install(u)));
    150     }
    151 }
  • 相关阅读:
    vscode 前端好用插件汇总
    IE8和IE9下textarea滚动选中的问题
    javascript实现数字整数位每三位一个逗号分隔
    简单枚举(算法竞赛入门经典)
    拓扑排序(算法竞赛入门经典)
    七桥问题--欧拉(算法竞赛入门经典)
    走迷宫问题 算法竞赛入门经典
    ZOJ1008
    ZOJ1163
    HDU 1069 Monkey and Banana
  • 原文地址:https://www.cnblogs.com/lightning34/p/4670283.html
Copyright © 2011-2022 走看看