DestinHistoire

 

BZOJ-1854 [Scoi2010]游戏(并查集)

题目描述

  \(n(n\leq 10^6)\) 个装备,每个装备都有 \(2\) 个属性,这些属性的值用 \([1,10000]\) 之间的数表示。只能使用装备的某一个属性,每种装备最多只能使用一次。 所使用的属性值必须从 \(1\) 开始连续递增地攻击。求最多能连续攻击多少次?

分析

  把每个武器的两个属性看成点,之间连边,让属性值大的作为父亲节点。每次读入一对点,如果两点的祖先相同说明形成了一个环,假设环的编号为 \(1\) ~ \(x\),则 \(x\) 个点可以全选择;如果没有两点祖先相同,说明形成了一条链,可以选择点 \(1\) ~ 点 \(x-1\)(编号最大的点不选)。在并查集每次合并的时候,将祖先编号小的合并到祖先编号大的,同时用 \(vis[i]\) 标记两点中编号小的点 \(i\) 可以到达,假设主函数中第一个无法到达的点为 \(x\),答案即为 $x-1 $。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e4;
int fa[N+10];
int get(int x)
{
    if(x==fa[x])
        return x;
    return fa[x]=get(fa[x]);
}
bool vis[N+10];
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=N;i++)
        fa[i]=i;
    for(int i=1;i<=n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        int fx=get(x),fy=get(y);
        if(fx!=fy)
        {
            if(fx>fy)
                swap(fx,fy);
            fa[fx]=fy;
        }
        vis[fx]=true;
    }
    for(int i=1;i<=N+1;i++)
    {
        if(!vis[i])
        {
            cout<<i-1<<endl;
            break;
        }
    }
    return 0;
}

posted on 2020-12-06 17:52  DestinHistoire  阅读(81)  评论(0)    收藏  举报

导航