抓捕盗窃犯

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

链接:https://ac.nowcoder.com/acm/contest/373/C
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

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

输入描述:

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

输出描述:

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

输入

复制
8 2
1 2 3 4 1 2 3 12
2 3 3 3 6 7 5 8

输出

复制
22

说明

对于样例一,一种可行的方案是:

在地点3、地点8分别设置一个哨卡,此时答案为1+2+3+4+12=22
示例2

输入

复制
8 2
1 2 3 4 5 6 7 8
2 3 4 5 6 7 8 8

输出

复制
36

说明

对于样例二,一种可行的方案是:

在地点2、地点8分别设置一个哨卡,此时答案为1+2+3+4+5+6+7+8=36

思路:就是并查集,自己也不是没学过并查集,但是却没想到这题是并查集来写,其中有一些处理很好,以前从来没看过这样处理的,先把属于一个块的分好,再遍历一遍N,这时把每个块的总和加到
根节点上,最后把这个总和存入容器中,排个序就是答案了。。。 自己真的很菜
看代码:
#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=1e5+50;
LL fa[maxn],sum[maxn];
LL a[maxn];
LL N,M;
bool cmp(const LL x,const LL y)
{
    return x>y;
}
void Init()
{
    memset(sum,0,sizeof(sum));
    for(LL i=1;i<=N;i++) fa[i]=i;
    return ;
}
LL Find(LL x)
{
    //cout<<"***"<<x<<endl;
    if(fa[x]==x) return fa[x];
    return fa[x]=Find(fa[x]);
}
void Union(LL x,LL y)
{
    LL fx=Find(x);
    LL fy=Find(y);
    if(fx!=fy) fa[fx]=fy;
    return ;
}
int main()
{
    vector<LL> ans;
    ans.clear();
    scanf("%lld%lld",&N,&M);
    Init();
    for(LL i=1;i<=N;i++)
    {
        scanf("%lld",&a[i]);
    }
    for(LL i=1;i<=N;i++)
    {
        LL x;
        scanf("%lld",&x);
        Union(i,x);
    }
    //cout<<"**"<<endl;
    for(LL i=1;i<=N;i++)
    {
        LL x=Find(i);
        sum[x]+=a[i];
    }
    //cout<<"*"<<endl;
    for(LL i=1;i<=N;i++)
    {
        if(fa[i]==i) ans.push_back(sum[i]);
    }
    sort(ans.begin(),ans.end(),cmp);
    //for(int i=0;i<ans.size();i++) cout<<ans[i]<<" ";
    //cout<<endl;
    LL asum=0;
    LL len=ans.size();
    for(LL i=0;i<min(M,len);i++) asum+=ans[i];
    printf("%lld
",asum);
    return 0;
}
当初的梦想实现了吗,事到如今只好放弃吗~
原文地址:https://www.cnblogs.com/caijiaming/p/10478680.html