【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\n", (str[0] == 'u' ? T::uninstall(u) : T::install(u)));
150     }
151 }

 

posted @ 2015-07-23 13:46  Lightning34  阅读(371)  评论(0编辑  收藏  举报