#sLPFybttg040503. 1562:「NOI2015」软件包管理器
1562:「NOI2015」软件包管理器
题目描述
你决定设计你自己的软件包管理器。软件包之间有依赖关系:如果软件包 依赖软件包 ,那么安装软件包 以前,必须先安装软件包 。同时,如果想要卸载软件包 ,则必须卸载软件包 。
除 号软件包以外,每个软件包都会依赖一个且仅一个软件包,而 号软件包不依赖任何一个软件包。依赖关系不存在环,也不会有一个软件包依赖自己。
现在你要为软件包管理器写一个依赖解决程序。根据反馈,用户希望在安装和卸载某个软件包时,快速地知道这个操作实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包)。注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为 。
输入格式
输入的第 行包含 个正整数 ,表示软件包的总数。软件包从 开始编号。
随后一行包含 个整数,相邻整数之间用单个空格隔开,分别表示 号软件包依赖的软件包的编号。
接下来一行包含一个正整数 ,表示询问的总数。
之后 行,每行一个询问。询问分为两种:
install x:表示安装软件包uninstall x:表示卸载软件包
你需要维护每个软件包的安装状态,一开始所有的软件包都处于未安装状态。对于每个操作,你需要输出这步操作会改变多少个软件包的安装状态,随后应用这个操作(即改变你维护的安装状态)。
输出格式
输出包括 行。 输出文件的第 行输出一个整数,为第 步操作中改变安装状态的软件包数。
样例
输入样例 1
7
0 0 0 1 1 5
5
install 5
install 6
uninstall 1
install 4
uninstall 0
输出样例 1
3
1
3
2
3
样例解释
依赖关系:
号软件包无依赖。
号软件包依赖 。
号软件包依赖 。
号软件包依赖 。
树结构:
0
/ | \
1 2 3
/ \
4 5
\
6
初始所有软件包未安装。
install 5:安装 需要先安装 (因为 依赖 , 依赖 )。安装 个软件包,输出 。install 6:安装 需要先安装 (因为 已安装),输出 。uninstall 1:卸载 需要卸载 (因为 依赖 ),输出 。install 4:安装 需要先安装 (因为 依赖 ),输出 。uninstall 0:卸载 需要卸载所有软件包(),输出 。
数据范围
时间限制:1000 ms
内存限制:262144 KB
提示
依赖关系形成一棵以 为根的树。每个软件包依赖它的父节点。
- 安装操作
install x:需要安装 以及 到根节点路径上所有未安装的软件包。因此,改变的数量 = 到根节点路径上未安装的节点数。 - 卸载操作
uninstall x:需要卸载 以及 的子树中所有已安装的软件包。因此,改变的数量 = 的子树中已安装的节点数。
我们可以用树链剖分维护每个节点的安装状态( 表示未安装, 表示已安装)。线段树维护区间和(即已安装的节点数)。
对于 install x:
- 查询 到根节点路径上已安装的节点数 。
- 该路径上的节点总数为 (如果根深度为 )。
- 未安装的节点数 = 路径总节点数 已安装节点数。
- 输出该值,并将路径上所有节点标记为已安装(区间赋值为 )。
对于 uninstall x:
- 查询 的子树中已安装的节点数 。
- 输出该值,并将子树中所有节点标记为未安装(区间赋值为 )。
由于需要区间赋值和区间求和,线段树需要支持懒标记(覆盖标记)。
注意:树链剖分时,路径查询需要从 向上跳到根,每次查询一条重链的区间和,并累加。
子树查询对应 DFS 序区间 。
时间复杂度:,对于 可以接受。