抓捕盗窃犯 (nowcoder.com)https://ac.nowcoder.com/acm/problem/22562
总体思路:
将每个可连通的地点均放入在同一个集合中,再求出每个集合中包括的人数,取最大的M个集合求和,时间复杂度o(N)
代码核心:
遍历1~n个地点,将i与v[i]合并,为了保证fa[i]与fa[v[i]]相同,选择将较大的地点合并到较小的地点。由于从1开始遍历,可连通的地点i的fa[i]一定为在其集合中的最小值,从而保证了一致性
for(int i=1;i<=n;i++) merge(max(i,v[i]),min(v[i],i));
完整代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int fa[N],v[N];
ll a[N],s[N];
int find(int x)
{
return (fa[x]==x?x:fa[x]=find(fa[x]));
}
void merge(int x,int y)
{
fa[find(x)]=find(y);
}
void solve()
{
int n,m;
ll ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>v[i];
for(int i=1;i<=n;i++) merge(max(i,v[i]),min(v[i],i));
for(int i=1;i<=n;i++) s[find(i)]+=a[i];
sort(s+1,s+n+1);
while(m--)
{
ans+=s[n];
n--;
}
cout<<ans;
}
int main()
{
solve();
return 0;
}