[11.11模拟赛]T1

setting

一次旅行结束后,罗伦斯购入了大量物品,并准备在本地拍卖。

Description

罗伦斯一共购入了(n)件物品,第(i)件物品的出售价格为(i)个崔尼银币。
每一个物品都有一些的用途,第(i)个物品存在最多一个(p_i),表示第(i)号物品的用途恰好包含了第(p_i)件物品的用途。
罗伦斯把这些物品按用途排列好,发现这恰好形成了一个森林,第(i)个物品的父亲是(p_i)
(m)个商人前来购买物品,第(i)个商人希望能买第(C_i)件,或者一件能代替(C_i)的物品(即(C_i)树中的物品),如果(C_i=0),那么表示这个商人想任意购买一件物品。
罗伦斯希望知道自己最多能赚多少钱。

Input

第一行两个整数 。
第二行(n)个数表示(p_i),如果(p_i=0),那就表示没有一个物品的用途被第(i)号物品的用途恰好包含,即(i)是一个根。
第三行(m)个数表示(C_i)

Output

Sample Input

3 3
3 0 0
2 0 2

Sample Output

5

Data Constraint

(n,mleq 3ast 10^6,0leq p_i,C_ileq n)
( ext{subtask 1 30pts}) (n) (leq) (2000)
( ext{subtask 2 27pts}) (n) (leq) (10 ^ 5)
( ext{subtask 3 23pts}) (n) (leq) (5ast 10 ^ 5)
( ext{subtask 4 20pts}) ( ext{无其他限制})

Solution

建树,把每个商人的需求离线到那个点上去(( ext{tag[x]++})
从点的序号从(n)(1)上倒着扫一遍,如果这个点或这个点的父亲有tag,则把答案加上,并减一个标记(( ext{tag[x]--})),边做边路径压缩
友情提醒:三年( ext{OI一场空}),不开( ext{long long})见祖宗。

Code

#include<bits/stdc++.h>
using namespace std;
#define N 10000010
#define int long long
int n, m, x, ans;
int fa[N], tag[N];
inline int read() {
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}
int find(int x) {
	if (tag[x] || fa[x] == x) return x;
	fa[x] = find(fa[x]);
	return fa[x];
}
signed main() {
	freopen("spice.in", "r", stdin);
	freopen("spice.out", "w", stdout);
	n = read(), m = read();
	for (register int i = 1; i <= n; ++i)
		fa[i] = read();
	for (register int i = 1; i <= m; ++i)
		++tag[read()];
	for (register int i = n; i >= 1; --i) {
		x = find(i);
		if (tag[x]) --tag[x], ans += i;
	}
	printf("%lld", ans);
	return 0;
}
只要有想见的人,就不是孤身一人了。
原文地址:https://www.cnblogs.com/Agakiss/p/11839554.html