918. 软件包管理器(树链剖分,@模板题)

Linux 用户和 OSX 用户一定对软件包管理器不会陌生。

通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安装所依赖的其它软件包),完成所有的配置。

Debian/Ubuntu 使用的 apt-get,Fedora/CentOS 使用的 yum,以及 OSX 下可用的 homebrew 都是优秀的软件包管理器。

你决定设计你自己的软件包管理器。

不可避免地,你要解决软件包之间的依赖问题。

如果软件包 A 依赖软件包 B,那么安装软件包 A 以前,必须先安装软件包 B。

同时,如果想要卸载软件包 B,则必须卸载软件包 A。

现在你已经获得了所有的软件包之间的依赖关系。

而且,由于你之前的工作,除 0 号软件包以外,在你的管理器当中的软件包都会依赖一个且仅一个软件包,而 0 号软件包不依赖任何一个软件包。

依赖关系不存在环(若有 m(m≥2) 个软件包 A1,A2,A3,…,Am,其中 A1 依赖 A2,A2 依赖 A3A3,A3 依赖 A4,……,Am−1 依赖 Am,而 Am 依赖 A1,则称这 m 个软件包的依赖关系构成环),当然也不会有一个软件包依赖自己。

现在你要为你的软件包管理器写一个依赖解决程序。

根据反馈,用户希望在安装和卸载某个软件包时,快速地知道这个操作实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包),你的任务就是实现这个部分。

注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为 0。

输入格式

输入文件的第 1 行包含 1 个正整数 n,表示软件包的总数。软件包从 0 开始编号。

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

接下来一行包含 1 个正整数 q,表示询问的总数。

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

  • install x:表示安装软件包 x
  • uninstall x:表示卸载软件包 x

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

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

输出格式

输出文件包括 q 行。

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

数据范围

1130_c73c6078ae-软件包管理器2.png

输入样例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
输入样例2:
10
0 1 2 1 3 0 0 3 2
10
install 0
install 3
uninstall 2
install 7
install 5
install 9
uninstall 9
install 4
install 1
install 9
输出样例2
1
3
2
1
3
1
1
1
0
1

 解析:

#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <utility>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <math.h>
#include <map>
#include <sstream>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <stdio.h>
#include <tuple>
using namespace std;
/*
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
*/
typedef long long LL;
//#define int long long
#define ld long double
//#define INT __int128
const LL INF = 0x3f3f3f3f3f3f3f3f;
typedef unsigned long long ULL;
typedef pair<long long, long long> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const int inf = 0x3f3f3f3f;
const LL mod = 998244353;
const ld eps = 1e-12;
const int N = 1e6 + 10, M = N + 10;
int n, m;
int w[N], nw[N];
int h[N], e[M], ne[M], idx;
int id[N], top[N], fa[N], siz[N], dep[N], son[N], tot;
struct TREE {
	int l, r;
	int fg;
	int  sum;
}tr[N<<2];
void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs1(int u, int f, int d) {
	//cout << "______________________" << u << endl;
	fa[u] = f, dep[u] = d, siz[u] = 1;
	for (int i = h[u]; i != -1; i = ne[i]) {
		int j = e[i];
		if (j == f)continue;
		dfs1(j, u, d + 1);
		siz[u] += siz[j];
		if (siz[son[u]] < siz[j])son[u] = j;
	}
}
void dfs2(int u, int t) {
	//cout << "______________" << u << endl;
	id[u] = ++tot, nw[tot] = w[u], top[u] = t;
	if (son[u])dfs2(son[u], t);
	for (int i = h[u]; i != -1; i = ne[i]) {
		int j = e[i];
		if (j == fa[u] || j == son[u])continue;
		dfs2(j, j);
	}
}
#define ls u<<1
#define rs u<<1|1
void build(int u, int l, int r) {
	tr[u].l = l, tr[u].r = r, tr[u].fg = -1;
	if (l == r) {
		return;
	}
	int mid = l + r >> 1;
	build(ls, l, mid), build(rs, mid + 1, r);
}
void up(int u) {
	tr[u].sum = tr[ls].sum + tr[rs].sum;
}
void down(int u) {
	if (tr[u].fg!=-1) {
		tr[ls].fg = tr[u].fg;
		tr[ls].sum = tr[u].fg * (tr[ls].r - tr[ls].l + 1);
		tr[rs].fg = tr[u].fg;
		tr[rs].sum = tr[u].fg * (tr[rs].r - tr[rs].l + 1);
		tr[u].fg = -1;
	}
}
void modify(int u, int l, int r,int d) {
	if (l <= tr[u].l && tr[u].r <= r) {
		tr[u].fg = d;
		tr[u].sum = d * (tr[u].r - tr[u].l + 1);
		return;
	}
	down(u);
	int mid = tr[u].l + tr[u].r >> 1;
	if (l <= mid)modify(ls, l, r, d);
	if (r > mid)modify(rs, l, r, d);
	up(u);
}
void updata(int x) {
	int rt = 1;
	while (top[x] != top[rt]) {
		if (dep[top[x]] < dep[top[rt]])swap(x, rt);
		modify(1, id[top[x]], id[x], 1);
		x = fa[top[x]];
	}
	if (dep[x] < dep[rt])swap(x, rt);
	modify(1, id[rt], id[x], 1);
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	cin >> n;
	memset(h, -1, sizeof h);
	for (int i = 2; i <= n; i++) {
		int a;
		cin >> a;
		a++;
		add(a, i);
	}
	//cout << "_________" << endl;
	dfs1(1,0,1);
	//cout << "_________" << endl;
	dfs2(1, 1);
	//cout << "+++++++++++++++++++++++++++++++++++++++" << endl;
	//for (int i = 1; i <= n; i++) {
	//	cout << id[i] << " ";
	//}
	//cout << endl;
	//cout << endl;
	//cout << endl;
	//cout << "+++++++++++++++++++++++++++++++++++++++" << endl;
	//for (int i = 1; i <= n; i++) {
	//	cout << son[i] << " ";
	//}
	//cout << endl;
	//cout << endl;
	//cout << endl;


	build(1, 1, n);
	cin >> m;
	char op[20];
	int x;
	while (m--) {
		cin >> op >> x;
		x++;
		if (!strcmp(op, "install")) {
			int a = tr[1].sum;
			updata(x);
			int b = tr[1].sum;
			cout << b - a << endl;
		}
		else {
			int a = tr[1].sum;
			modify(1, id[x], id[x] + siz[x] - 1, 0);
			int b = tr[1].sum;
			cout << a - b << endl;
		}
	}
	return 0;
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值