[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,m\leq 3\ast 10^6,0\leq p_i,C_i\leq n\)
\(\text{subtask 1 30pts}\) \(n\) \(\leq\) \(2000\)
\(\text{subtask 2 27pts}\) \(n\) \(\leq\) \(10 ^ 5\)
\(\text{subtask 3 23pts}\) \(n\) \(\leq\) \(5\ast 10 ^ 5\)
\(\text{subtask 4 20pts}\) \(\text{无其他限制}\)

Solution

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

猜你喜欢

转载自www.cnblogs.com/Agakiss/p/11839554.html