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