BSOJ1153【liyunhui模拟试题】德雷克的逃生

题目描述

德雷克开始了他的奇妙冒险!
德雷克在新的地宫中迷路了!
新的地宫要坍塌了!
……
德雷克,不知道为什么炒鸡重,上哪座桥哪座桥塌,踩哪块石头哪块石头落,成就了物体承重力新单位1德雷克的男人,酷爱冒险。正如前文所说,这一次,他被困在了一个将要塌陷的地宫里。现在,你要扮演的角色是在地宫外提供远程协助&放哨的苏利文。你手上有地宫的一份地图。因为某种原因,你知道地宫中隧道的崩塌顺序。因为不知道德雷克在地宫的哪个房间,你需要计算出地宫不能连通的时刻,并通过一次喊破喉咙的喊叫让德雷克知道。

输入输出格式

输入格式
输入文件第一行包括三个整数 n ,$m, q,n代表地宫的房间数量,m代表地宫的隧道数量,q表示坍塌的隧道数。
接下来m行每行两个整数i, j,表示地宫的一条连接房间i, j的双向隧道。
接下来q行每行一个整数p,表示前述第p条隧道坍塌。保证按坍塌顺序给出。
输出格式
输出文件包括一行。如果到最后仍连通,输出q+1(数字);如果一开始就不连通,输出0;否则输出使地宫不能连通的那一次坍塌的顺序号。

输入输出样例

输入样例

4 5 4
1 3
1 2
2 3
2 4
3 4
5
3
2
1

输出样例

3

说明

对于40%的数据,满足 n <= 500, m <= 1000;
对于100%的数据,满足 n <= 500000, m <= 1000000, q <= m。

题目来源

liuyunhui123


分析

这道题本来想用Tarjan求割边,看到数据范围之后果断采用并查集。原本想对询问用二分查找,发现没必要,最后复杂度O(n)。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register ll
ll n,m,q,fa[500005],ask[1000005],total,vis[1000005];
struct did{
    ll u,v;
}e[1000005];
inline ll read()
{
    re luoyang=0,yz=1;
    char did=getchar();
    while(!isdigit(did)){if(did=='-')yz=-1;did=getchar();}
    while(isdigit(did)) luoyang=luoyang*10+did-'0',did=getchar();
    return luoyang*yz;
}
inline ll getfa(ll x)
{
    return fa[x]==x?x:fa[x]=getfa(fa[x]);
}
inline void merge(ll x,ll y)
{
    re fx=getfa(x),fy=getfa(y);
    if(fx!=fy)total--,fa[fy]=fx;
}
int main()
{
    total=n=read();m=read();q=read();
    for(re i=1;i<=n;i++)
    fa[i]=i;
    for(re i=1;i<=m;i++)
    {
        e[i].u=read(),e[i].v=read();
    }
    for(re i=1;i<=q;i++)
    ask[i]=read(),vis[ask[i]]=1;
    for(re i=1;i<=m;i++)
    if(!vis[i])
    merge(e[i].u,e[i].v);
    if(total==1)
    {
        cout<<q+1;
        return 0;
    }
    for(re i=q;i>=1;i--)
    {
        merge(e[ask[i]].u,e[ask[i]].v);
        if(total==1) 
        {
            cout<<i<<endl;
            return 0;
        }
    }
    cout<<0<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/disangan233/article/details/81076290