1. 程式人生 > >【JZOJ A組】聽我說,海蝸牛

【JZOJ A組】聽我說,海蝸牛

Description
在這裡插入圖片描述

Input
在這裡插入圖片描述

Output
在這裡插入圖片描述

Sample Input
4 4 3
1 4
1 2
1 3
2 3
4
1 2 3 4
3
1 2 3
2
1 2

Sample Output
2
3
2

Data Constraint
在這裡插入圖片描述
思路

正解就是爆搜!我比賽忘記判反向邊了

首先,想存下所有邊是不可能的,所以只能存被刪去的邊。
然後bfs時,用二分判斷這條邊是否相連。

但是,我們發現每搜一個點,就要詢問所有點是否相連或是否已去過,是O(ki^2)複雜度,只要資料極限就炸了!所以要用巧妙的方法來存沒到達的點。

我是開兩個佇列,每搜到一個點遍歷一遍佇列Q,如果那兩點之間的邊被刪了,就加入佇列q。結束時再把佇列q裡面的元素加入佇列Q。

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=3e5+77;
struct E
{
	int x,y;
}e[maxn];
int b[maxn],b1[maxn],n,m,t,cnt=0;
vector<int> a[maxn];
queue<int> Q;
bool cmp(E x,E y)
{
	return (x.x<y.x)||(x.x==y.x&&x.y<y.y);
}
int find(int p,int x)
{
	int l=0,r=a[p].size()-1;
	if(l>r) return 0x3f3f3f3f;
	while(l<=r)
	{
		if(l==r) return a[p][l];
		int mid=(l+r)>>1;
		if(a[p][mid]>x) r=mid-1;else
		if(a[p][mid]<x) l=mid+1;else
		if(a[p][mid]==x) return a[p][mid];
	}
	return a[p][l];
}
void bfs(int x)
{
	queue<int> qq,q;
	while(!qq.empty()) qq.pop();
	while(!q.empty()) q.pop();
	qq.push(x);
	while(!qq.empty())
	{
		int u=qq.front(); qq.pop();
		while(!Q.empty())
		{
			int v=Q.front(); Q.pop();
			if(find(u,v)!=v) qq.push(v); 
			else q.push(v);
		}
		while(!q.empty())
		{
			int u=q.front(); q.pop(); Q.push(u);
		}
	}
}
int main()
{
	freopen("connect.in","r",stdin); freopen("connect.out","w",stdout);
	scanf("%d%d%d",&n,&m,&t);
	for(int i=1; i<=m; i++)
	{
		cnt++;
		scanf("%d%d",&e[cnt].x,&e[cnt].y);
		cnt++;
		e[cnt].x=e[cnt-1].y; e[cnt].y=e[cnt-1].x;
	}
	sort(e+1,e+cnt+1,cmp);
	for(int i=1; i<=cnt; i++) a[e[i].x].push_back(e[i].y);
	while(t--)
	{
		int k,ans=0;
		scanf("%d",&k);
		while(!Q.empty()) Q.pop();
		for(int i=1; i<=k; i++)
		{
			int p;
			scanf("%d",&p); Q.push(p);
		}
		while(!Q.empty())
		{
			int u=Q.front(); Q.pop();
			bfs(u); ans++;
		}
		printf("%d\n",ans);
	}
}