并查集(抓捕犯人)

链接:https://ac.nowcoder.com/acm/problem/22562
来源:牛客网

Q市发生了一起特大盗窃案。这起盗窃案是由多名盗窃犯联合实施的,你要做的就是尽可能多的抓捕盗窃犯。
已知盗窃犯分布于 N个地点,以及第 i个地点初始有ai名盗窃犯。
特别的是,对于每一个地点 u,都有一个固定的地点 v当前如果某个盗窃犯位于地点 u,在下一个时刻他会移动到地点 v
你需要通过初始时在某些点设置哨卡来捉住他们。
现在你可以在 M个地点设置哨卡,如果在某个地点设置哨卡,你可以抓获在任一时刻经过该地点的盗窃犯。
也就是说,哨卡存在的时间是无限长,但哨卡不能移动。

输入描述:

第一行两个整数 N,M(1≤N,M≤105))。
第二行 N个整数 a1a2...aN,表示第 i个地点初始有 ai名盗窃犯。
第三行 N个整数 v1v2...vN,表示当前处于地点 i的盗窃犯下一个时刻会移动到地点 vi

输出描述:

输出一行一个整数--能够抓捕到的最大数量。



这个题就是一个并查集
#include<iostream>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=1e6+100;
int a[maxn];
int r[maxn];
int pre[maxn];
int b[maxn];
ll v[maxn];
bool cmp(ll a,ll b){
    return a>b;
}
int find(int x){
    if(pre[x]==x){
        return pre[x];
    }
    else{
        return pre[x]=find(pre[x]);
    }
}
void marge(int x,int y){
    int h1=find(x);
    int h2=find(y);
    if(h1==h2) return ;
    if(r[h1]<r[h2]) {
        pre[h1]=h2;
        r[h2]+=r[h1]; 
    } 
    else{
        pre[h2]=h1;
        r[h1]+=r[h2];
    }
}
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        pre[i]=i;
        r[i]=1;
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&b[i]);
        marge(i,b[i]);
    }
    for(int i=1;i<=n;i++){
        int p=find(i);
        v[p]=1ll*(v[p]+a[i]);
    }
    sort(v+1,v+n+1,cmp);
    ll ans=0;
    for(int i=1;i<=m;i++){
        ans+=v[i];
    }
    printf("%lld",ans);
}


原文地址:https://www.cnblogs.com/lipu123/p/14124781.html