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;
}