【并查集】【P1525】关押罪犯

传送门

Description

Input

Output

Sample Input

4 6
1 4 2534
2 3 3512
1 2 28351
1 3 6618
2 4 1805
3 4 12884

Sample Output

3512

Hint

Solution

  非常显然的并查集题目,在本题中,对于每个罪犯i,维护两个信息:必须要和他关在一起的罪犯的集合,以及和他有仇的罪犯的集合,由于监狱只有两个,所以和他有仇的罪犯一定被关在同一个集合里面。sort一遍贪心从上到下扫描。对于不得不管起来的两个有仇的人即为答案。

Code

复制代码
#include<cstdio>
#include<algorithm>
namespace read{
    void imop(int&x){
        char ch=getchar();
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9')   x=x*10+ch-'0',  ch=getchar();
        return;
    }
    void op(int&x){
        char ch=getchar();
        int f=1;
        while(ch<'0'||ch>'9'){
            if(ch=='-') f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')   x=x*10+ch-'0',  ch=getchar();
        x*=f;
        return;
    }
}
namespace fusu{
    const int maxn = 20010 , maxm = 100010;
    struct Crim{
        int a,b,value;
    };
    Crim criminal[maxm];
    int n,m;
    inline bool cmp(Crim a,Crim b){return a.value<b.value;}
    int frog[maxn],enemy[maxn];
    inline int find(int x){
        if(frog[x]^x)    frog[x]=find(frog[x]);
        return frog[x];
    }
    void gather(int a,int b){
        int fa=find(frog[a]),fb=find(frog[b]);
        frog[fa]=fb;
        return;
    }
    void beginning(){
        for(int i=1;i<=n;++i)
            frog[i]=i;
        return;
    }
    int doit(){
        read::imop(n);read::imop(m);
        for(int i=1;i<=m;++i){
            read::imop(criminal[i].a);
            read::imop(criminal[i].b);
            read::imop(criminal[i].value);
        }
        std::sort(criminal+1,criminal+1+m,cmp);
        beginning();
        do{
            int fa=find(frog[criminal[m].a]),fb=find(frog[criminal[m].b]);
            if(!(fa^fb)){
                printf("%d\n",criminal[m].value);
                return 0;
            }
            if(!enemy[criminal[m].a])    enemy[criminal[m].a]=criminal[m].b;
                else gather(enemy[criminal[m].a],criminal[m].b);
            if(!enemy[criminal[m].b])    enemy[criminal[m].b]=criminal[m].a;
                else gather(enemy[criminal[m].b],criminal[m].a);
            --m;
        }while(m);
        printf("0\n");
        return 0;
    }
}
int main(){
    return fusu::doit();
}
复制代码

Summary

对于并查集中的补集法,对于每个个体记录多个信息,在合并时合并多个信息即可。

posted @   一扶苏一  阅读(340)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示