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

题目背景

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

题目描述

你决定设计你自己的软件包管理器。不可避免地,你要解决软件包之间的依赖问题。如果软件包 aa 依赖软件包 bb,那么安装软件包 aa 以前,必须先安装软件包 bb。同时,如果想要卸载软件包 bb,则必须卸载软件包 aa。

现在你已经获得了所有的软件包之间的依赖关系。而且,由于你之前的工作,除 00 号软件包以外,在你的管理器当中的软件包都会依赖一个且仅一个软件包,而 00 号软件包不依赖任何一个软件包。且依赖关系不存在环(即不会存在 mm 个软件包 a_1,a_2, \dots , a_ma1​,a2​,…,am​,对于 i<mi<m,a_iai​ 依赖 a_i+1ai​+1,而 a_mam​ 依赖 a_1a1​ 的情况)。

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

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

输入格式

第一行一个正整数 nn,表示软件包个数,从 00 开始编号。
第二行有 n-1n−1 个整数,第 ii 个表示 ii 号软件包依赖的软件包编号。
然后一行一个正整数 qq,表示操作个数,格式如下:

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

一开始所有软件包都是未安装的。

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

输出格式

输出 qq 行,每行一个整数,表示每次询问的答案。

输入输出样例

输入 #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

 

 

一眼看去似乎没办法单独开个数组维护每个点的状态(安装/未安装), 实际上我们浪费点时间单点查询一下也不会超时

查到状态以后再树剖查询结果就出来了

注: 查询时的区间一定要是$[ id[l], id[r] ], query(id[l], id[r], 1, n, 1)$, 而不是$[l, r], query(l, r, 1, n, 1)$

后者虽然说可能能过所有样例, 但这样查询到的结果是不正确的, 一定要记得用$id[l], id[r]$作为区间左右端点

如果过了样例却过不了题可以看看是不是犯了上面这个错误

 

ac code
#include <iostream>
#include <algorithm>
using namespace std;

typedef int nit, it, itn;
typedef long long ll;
constexpr int MAXN = 1e5 + 7, inf = 0x3f3f3f3f;

ll sum[MAXN << 2], lazy[MAXN << 2], a[MAXN], nid[MAXN], n, m;
int h[MAXN], ne[MAXN << 1], e[MAXN << 1], at[MAXN], idx;
int top[MAXN], id[MAXN], son[MAXN], tmp[MAXN], R[MAXN], fa[MAXN], Size[MAXN], deep[MAXN], cnt, ncnt;
void add(int u, int v)
{
	e[++idx] = v;
	ne[idx] = h[u];
	h[u] = idx;
}

void pushup(int rt)
{
	sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}

void pushdown(int rt, int len)
{
	if (lazy[rt])
	{
		lazy[rt << 1] = lazy[rt];
		lazy[rt << 1 | 1] = lazy[rt];

		sum[rt << 1] = lazy[rt] == 1 ? len - (len >> 1) : 0;
		sum[rt << 1 | 1] = lazy[rt] == 1 ? len >> 1 : 0;

		lazy[rt] = 0;
	}
}

void build(int l, int r, int rt)
{

	if (l == r)
	{
		sum[rt] = 0;
		return;
	}
	int mid = l + r >> 1;
	build(l, mid, rt << 1);
	build(mid + 1, r, rt << 1 | 1);
	pushup(rt);
}
ll query(int a, int b, int l, int r, int rt)
{
	if (a <= l && r <= b)
		return sum[rt];
	pushdown(rt, r - l + 1);
	ll ans = 0;
	int mid = l + r >> 1;
	if (a <= mid)
		ans += query(a, b, l, mid, rt << 1);
	if (b > mid)
		ans += query(a, b, mid + 1, r, rt << 1 | 1);
	return ans;
}

void update(int pos, int c)
{
	sum[nid[pos]] += c;
	int t = nid[pos] >> 1, Size = 2;
	while (t)
	{
		pushup(t);
		pushdown(t, Size);
		t >>= 1;
		Size <<= 1;
	}
}

void update(int a, int b, int install, int l, int r, int rt)
{
	if (a <= l && r <= b)
	{
		if (install == 1)
			sum[rt] = r - l + 1;
		else
			sum[rt] = 0;
		lazy[rt] = install;
		return;
	}

	pushdown(rt, r - l + 1);
	int mid = l + r >> 1;
	if (a <= mid)
		update(a, b, install, l, mid, rt << 1);
	if (b > mid)
		update(a, b, install, mid + 1, r, rt << 1 | 1);
	pushup(rt);
}
ll pathquery(int x, int y, int install)
{
	ll ans = 0, tmp;

	while (top[x] != top[y])
	{
		if (deep[top[x]] < deep[top[y]])
		{
			swap(x, y);
		}
		tmp = query(id[top[x]], id[x], 1, n, 1);
		ans += (install == 1 ? id[x] - id[top[x]] + 1 - tmp : tmp);

		x = fa[top[x]];
	}
	if (deep[x] > deep[y])
		swap(x, y);
	tmp = query(id[x], id[y], 1, n, 1);
	ans += (install == 1 ? id[y] - id[x] + 1 - tmp : tmp);
	return ans;
}

void pathupdate(int x, int y, int install)
{

	while (top[x] != top[y])
	{
		if (deep[top[x]] < deep[top[y]])
		{
			swap(x, y);
		}
		update(id[top[x]], id[x], install, 1, n, 1);

		x = fa[top[x]];
	}
	if (deep[x] > deep[y])
		swap(x, y);
	update(id[x], id[y], install, 1, n, 1);
}

void sonupdate(int x, int install)
{
	update(id[x], id[x] + Size[x] - 1, install, 1, n, 1);
}

ll sonquery(int x)
{
	return query(id[x], id[x] + Size[x] - 1, 1, n, 1);
}

void dfs1(int x, int f, int dep)
{
	deep[x] = dep;
	Size[x] = 1;
	fa[x] = f;
	int maxson = -1;
	for (int i = h[x]; i; i = ne[i])
	{
		int y = e[i];
		if (y != f)
		{
			dfs1(y, x, dep + 1);
			Size[x] += Size[y];
			if (maxson < Size[y])
			{
				son[x] = y;
				maxson = Size[y];
			}
		}
	}
}

void dfs2(int x, int f)
{
	id[x] = ++cnt;
	at[cnt] = a[x];
	tmp[cnt] = x;
	top[x] = f;
	if (!son[x])
		return;
	dfs2(son[x], f);
	for (int i = h[x]; i; i = ne[i])
	{
		int y = e[i];
		if (y != fa[x] && y != son[x])
			dfs2(y, y);
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int pos, t, l, r, u, v, rt = 1;
	ll x, ans;
	string op;
	cin >> n;

	for (int i = 2; i <= n; ++i)
	{
		cin >> u;
		u++;
		add(i, u);
		add(u, i);
	}
	dfs1(rt, 0, 1);
	dfs2(rt, rt);
	build(1, n, 1);

	cin >> m;
	while (m--)
	{
		ans = 0;
		cin >> op >> pos;
		pos++;
		int vis = query(id[pos], id[pos], 1, n, 1);
		if (op[0] == 'i' && !vis)
		{
			ans = pathquery(pos, rt, 1);
			pathupdate(pos, rt, 1);
		}
		else if (op[0] == 'u' && vis)
		{
			ans = sonquery(pos);
			sonupdate(pos, -1);
		}
		cout << ans << '\n';
	}

	return 0;
}

 

上一篇:Codeforces Round #727 (Div. 2)部分题解(A-D)


下一篇:LeetCode 每日一题 (两数相加)