存在
这道题想到方法之后就很简单了,是一道图论建模题。考虑将不喜欢的关系抽象成一条有向边,不难发现每个点都有且仅有一条出边,则最后形成的图在形态上一定类似一个基环树森林,或者说在形成的图中每一个连通块内最多含有一个环。
不难想到对于无环的一定有合法方案使得每一个点都不会有不喜欢的在其之前,对于环上的则一定至少需要破坏一条环上的边。于是我们跑一个类似拓朴排序的东西即可,对于无环的直接丢弃,有环的在环上找到边权最小的一条边保留即可。
xxxxxxxxxx
861
2
3
4
5
6
7
8
9
10
11using namespace std;
12
13mt19937 rnd(random_device{}());
14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
15bool rnddd(int x){return rndd(1, 100) <= x;}
16
17typedef unsigned int uint;
18typedef unsigned long long unll;
19typedef long long ll;
20typedef long double ld;
21
22template < typename T = int >
23inline T read(void);
24
25struct Edge{
26 Edge *nxt;
27 int to;
28 int val;
29 OPNEW;
30}ed[210000];
31ROPNEW(ed);
32Edge* head[210000];
33
34int N;
35bitset < 210000 > vis;
36int ind[210000];
37ll ans(0);
38
39int main(){
40 N = read();
41 for(int i = 1; i <= N; ++i){
42 int s = i, t = read();
43 head[s] = new Edge{head[s], t};
44 ++ind[t];
45 }for(int i = 1; i <= N; ++i)head[i]->val = read();
46 queue < int > cur;
47 for(int i = 1; i <= N; ++i)if(!ind[i])vis[i] = true, cur.push(i);
48 while(!cur.empty()){
49 int tp = cur.front(); cur.pop();
50 for(auto i = head[tp]; i; i = i->nxt){
51 --ind[SON];
52 if(!ind[SON])vis[SON] = true, cur.push(SON);
53 }
54 }
55 for(int i = 1; i <= N; ++i){
56 if(!vis[i]){
57 int mn(INT_MAX);
58 vis[i] = true;
59 auto cur = head[i];
60 while(cur->to != i){
61 vis[cur->to] = true;
62 mn = min(mn, cur->val);
63 cur = head[cur->to];
64 }mn = min(mn, cur->val);
65 ans += mn;
66 }
67 }printf("%lld\n", ans);
68 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
69 return 0;
70}
71
72template < typename T >
73inline T read(void){
74 T ret(0);
75 int flag(1);
76 char c = getchar();
77 while(c != '-' && !isdigit(c))c = getchar();
78 if(c == '-')flag = -1, c = getchar();
79 while(isdigit(c)){
80 ret *= 10;
81 ret += int(c - '0');
82 c = getchar();
83 }
84 ret *= flag;
85 return ret;
86}
update-2022_12_08 初稿