Description
Assume N (N <= 10^5) criminals are currently in Tadu City, numbered from 1 to N. And of course, at least one of them belongs to Gang Dragon, and the same for Gang Snake. You will be given M (M <= 10^5) messages in sequence, which are in the following two kinds:
1. D [a] [b]
where [a] and [b] are the numbers of two criminals, and they belong to different gangs.
2. A [a] [b]
where [a] and [b] are the numbers of two criminals. This requires you to decide whether a and b belong to a same gang.
Input
Output
Sample Input
1
5 5
A 1 2
D 1 2
A 1 2
D 2 4
A 1 4
Sample Output
Not sure yet.
In different gangs.
In the same gang.
花了一些力氣,終於把這個經典的題弄懂了,感謝TR學長的解答。
在這之前先拿一道經典的題拋磚引玉:
有N個人,M個關係,每個關係由a, b, c三個量描述,表示a與b的關係是c。當c爲0時表示a,b是朋友,當c爲1時表示a, b是敵人。已知關係具有傳遞性,也就是說a, b是朋友以及a, d是朋友的時候b, d是朋友。a, b是敵人以及a, d是朋友的時候b, d是敵人。問題給的M條關係是否成立,若成立則輸出"YES",否則輸出"NO",並輸出最早在給出第幾條關係的時候可以確定關係不成立。
(N, M <= 10^5, a, b <= N, a != b, c = 0, 1)
大概就是說:如果讓並查集維護朋友關係是很簡單的,a,b是朋友,b,c是朋友,用並查集的unit操作+find詢問,很容易知道a,c是朋友,但是我該怎麼維護敵人關係。我們考慮引入輔助元素,例如i是它本尊,i+N是它的宿敵。當然這個宿敵是不存在的,是我們虛擬出來的。
a,b是敵人的話,那麼unit(a,b+N),unit(b,a+N),爲什麼?如果a和b的宿敵是朋友,那麼a和b就是敵人了。記住,並查集永遠只維護朋友關係。
a,b是朋友的話:同理,我就unit(a,b),unit(a+N,b+N)。
怎樣判斷信息是錯誤的?如果a和a的宿敵當朋友了,換句話說,就是與前面的信息矛盾了,就說明信息是錯的。
這題自己的code:
#include<cstdio>
const int MAXN=1e5+5;
int par[2*MAXN];
int find(int x){
return par[x]==x?par[x]:find(par[x]);
}
void unit(int x,int y){
x=find(x);y=find(y);
if(x!=y)par[x]=y;
}
int main(){
int N,M;scanf("%d%d",&N,&M);
for(int i=0;i<2*N;++i)
par[i]=i;
int i;
for(i=0;i<M;++i){
int a,b,c;scanf("%d%d%d",&a,&b,&c);
if(c==0){
if(find(a)==find(b+N)||(find(a+N)==find(b)))break;
unit(a,b);
unit(a+N,b+N);
}
if(c==1){
if(find(a)==find(b)||find(a+N)==find(b+N))break;
unit(a,b+N);
unit(a+N,b);
}
}
printf("%d\n",i+1);
}
好了,如果上面的理解清楚了,那麼這個題就不難了。
code:
#include<cstdio>
const int MAXN=1e5+5;
int par[MAXN*2];
int find(int x){
return par[x]==x?par[x]:par[x]=find(par[x]);
}
void unite(int x,int y){
x=find(x);y=find(y);
if(x!=y)par[x]=y;
}
int main(void){
int T;scanf("%d",&T);
while(T--){
int N,M;scanf("%d%d",&N,&M);getchar();
for(int i=0;i<2*N;++i)
par[i]=i;
for(int i=0;i<M;++i){
char ch;int a,b;
scanf("%c%d%d",&ch,&a,&b);getchar();
if(ch=='A'){
if(find(a)==find(b))printf("In the same gang.\n");
else if(find(a)==find(N+b))printf("In different gangs.\n");
else printf("Not sure yet.\n");
}else{
unite(a,b+N);
unite(a+N,b);
}
}
}
}