RBQOJ727亲戚

先安利一波好oj->这里

【问题描述】

老爸出差了,你和你的妈妈准备去走人家,但是你的亲戚们数量太多了,关系网过於庞大,要判断两个是否是亲戚,确实还很不容易,现在给出一些消息,你想知道某两人是否是亲戚关系

规定:如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚,

如:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。

但是由于亲戚们的感情并不是总是那么好的,所以随时会出现反目的现象。倘若某对亲戚反目了,x的亲戚和y的亲戚也就不再是亲戚。

如:x,y反目了,y,z是亲戚,x,z就不是亲戚。

由于亲戚们的性格不是那么好(有点2),所以他们在反目之后就不会再和好。他们各自的亲戚们也不会再成亲戚。

如:x和y反目了,x的亲戚就不会和y的亲戚再成亲戚关系。

在这里,只有直接的亲戚才会反目(废话,不直接的亲戚他们认都不认识,怎么会反目?!)同时我们保证不存在有一个人两难的情况

两难:假设z既是x的直接亲戚,又是y的直接亲戚,那x和y反目后,z就会出现两难的情况。

另外,我们规定自己是自己的亲戚。

输入格式

第一行包含两个正整数n、m、q分别表示有n个人,m个消息,q对亲戚

以下m行:每行两个数Mi,Mj(1<=Mi,Mj<=N),表示Mi和Mj是亲戚。

接着q行,每行一个字符串C和两个数Mi,Mj(1<=Mi,Mj<=N)

如果C=’A’,表示询问Mi和Mj是否为亲戚。

如果C=’F’,表示Mi和Mj反目了(保证Mi和Mj是直接亲戚关系)

输出格式

若干行,对于每个询问输出’Yes’表示他们是亲戚,或’No’表示他们不是亲戚




很裸的一道离线处理并查集,先读入开始的所有边,然后将每条边的小端点作为map的第一位,大端点作为第二位,存下当前边的编号,再读入所有操作,记录需要删的边,用map确定编号,让vis当前编号=1,然后下面开始构图,如果当前边的vis不是1,那么合并两个端点集合,否则continue,然后将所有操作逆序进行,读到删边操作,用map确定要删哪条边,然后把这条边加进来,读到判断操作,就将判断结果加入ans就好了

代码

#include<map>
#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=40000;
map<int,int>jud[M];//确定编号
struct edge
{
	int a,b;
}emm[M];//存初始边
struct que
{
	int a,b;
	char s;
}gll[M];//存操作
int fa[M],si[M],ans[M];
int n,m,q,cnt,vis[M];
int find(int x)
{
	if (fa[x]!=x) return fa[x]=find(fa[x]);
	return x;
}//路径压缩
void unionn(int a,int b)
{
	if (si[a]<=si[b]) fa[a]=b,si[b]+=si[a];
	else fa[b]=a,si[a]+=si[b];
	return ; 
}//按秩合并
void constt()
{
	for (int i=1;i<=n;i++) fa[i]=i,si[i]=1;
	return ;
}//初始化
int main()
{
	scanf("%d%d%d",&n,&m,&q);constt();
	for (int i=1;i<=m;i++)
	{
		int x,y;scanf("%d%d",&x,&y);
		emm[i].a=min(x,y);emm[i].b=max(x,y);
		jud[emm[i].a][emm[i].b]=i;//存入编号
	}
	for (int i=1;i<=q;i++)
	{
		char fu;int x,y;
		scanf("%s %d %d",&fu,&x,&y);
		gll[i].s=fu;gll[i].a=min(x,y);gll[i].b=max(x,y);
		if (fu=='F') vis[jud[gll[i].a][gll[i].b]]=1;
	}//确定哪条边不加入
	for (int i=1;i<=m;i++)
	{
		if (vis[jud[emm[i].a][emm[i].b]]) continue;
		int r1=find(emm[i].a);
		int r2=find(emm[i].b);
		if(r1!=r2) unionn(r1,r2);
	}//构图
	for (int i=q;i>0;i--)
	{
		int r1=find(gll[i].a);
		int r2=find(gll[i].b);
		if (gll[i].s=='F') unionn(r1,r2);
		else if (r1==r2) ans[i]=1;
		else if (r1!=r2) ans[i]=2;
	}//执行操作
	for (int i=1;i<=q;i++)
	if (ans[i]==1) puts("Yes");
	else if (ans[i]==2) puts("No");
	return 0;
}



猜你喜欢

转载自blog.csdn.net/acerandaker/article/details/80715651
今日推荐