并查集 牛客练习赛41 C抓捕盗窃犯

题目链接 :https://ac.nowcoder.com/acm/contest/373/C

题意,初始每一个城市都有一伙盗贼,没过一个时刻盗贼就会逃窜到另一个城市,你可以在m个城市设置监察站,会逮捕所有经过该城市的盗贼

分析:仔细分细题目,因为每个城市的盗贼都是流动的,这就可能会形成环,而如果成环的话,在环所在任一城市都可以把这批城市的全部盗贼逮捕,就不需要再环上设多个监察站了,进一步推广,因为可以自己往自己的城市跑,所以也有可能是链,而链也是满足设一个监察站可以逮捕所有

自然想到引入并查集,用map来保存

 1 #include <bits/stdc++.h>
 2 using  namespace  std;
 3 typedef long long ll;
 4 const int maxn=1e5+7;
 5 const int mod=1e9+7;
 6 ll a[maxn],v[maxn];
 7 ll par[maxn];
 8 ll rnk[maxn];
 9 ll c[maxn];
10 bool cmp(const ll &a,const ll &b){
11     return a>b;
12 }
13 void init(){
14     for(ll i=0;i<maxn;i++) par[i]=i,rnk[i]=0;    
15 }
16 ll find(ll x){
17     if(par[x]==x){
18         return x;
19     }
20     else{
21         return par[x]=find(par[x]);
22     }
23 }
24 void unite(ll x,ll y){
25     x=find(x);y=find(y);
26     if(x==y) return ;
27     if(rnk[x]<rnk[y]){
28         par[x]=y;
29     }else {
30         par[y]=x;
31         if(rnk[x]==rnk[y]) rnk[x]++;
32     }
33 }
34 bool same(ll x,ll y){
35     return find(x)==find(y);
36 }
37 int  main(){  
38     ll n,m;scanf("%lld%lld",&n,&m);
39     init();
40     for(int i=1;i<=n;i++){
41         scanf("%lld",&a[i]);
42     }
43     for(int i=1;i<=n;i++){
44         scanf("%lld",&v[i]);
45         unite(i,v[i]);
46     }
47     map<ll,ll> ans;
48     map<ll,ll>::iterator ite;
49     for(ll i=1;i<=n;i++){
50         ans[find(i)]+=a[i];
51     }
52     //for(int i=1;i<=n;i++) cout<<find(i)<<" ";
53     int j=0;
54     for(ite=ans.begin();ite!=ans.end();++ite){
55         c[j++]=ite->second;
56     }
57     sort(c,c+ans.size(),cmp);
58     ll cnt=0;
59     for(ll i=0;i<m&&i<ans.size();i++){
60     cnt+=c[i];}//cout<<c[i]<<endl;}
61     cout<<cnt<<endl;
62     return 0;
63 }

猜你喜欢

转载自www.cnblogs.com/qingjiuling/p/10458977.html