1. 程式人生 > 實用技巧 >【USACO19Feb-S】偉大的植被恢復The Great Revegetation - 種類並查集

【USACO19Feb-S】偉大的植被恢復The Great Revegetation - 種類並查集

Description

  一場漫長的乾旱使農場主約翰的N牧場沒有草。然而,隨著雨季的到來,是時候“重新種植”了。在農夫約翰的小屋裡,他有兩個桶,每個桶都有不同型別的草籽。他想在他的每一個N牧場種草,在每一個牧場中選擇一種型別的草。

  作為一名奶農,農場主約翰想確保他能滿足他那幾頭奶牛的特殊飲食需求。他的每頭m奶牛都有兩個最喜歡的牧場。他的一些奶牛有一個飲食限制,那就是他們應該只吃一種型別的草,因此農場主約翰希望確保在這類奶牛最喜歡的兩個田裡種植同一種類型的草。其他的奶牛有一個非常不同的飲食限制,要求他們吃不同型別的草。對於那些奶牛,農場主約翰當然想確保他們最喜歡的兩塊田地裡有不同的草。

  請幫助農場主約翰確定他在他的N牧場上種植草的不同方式的數量。

Input

  輸入的第一行包含N(2≤n≤105)和m(1≤m≤105)。
  下一行m中的每一行都包含一個“s”或“d”字元,後跟兩個1…n範圍內的整數,描述農場主約翰的一頭牛最喜歡的兩個牧場。如果字元是“s”,則這一行表示一頭母牛在其兩個最喜愛的牧場中需要相同型別的草。如果字元為“d”,則該行表示需要不同草型別的奶牛。

Output

  輸出農場主約翰在他的N牧場上植草的方式。請用二進位制寫你的答案。

Sample Input

3 2
S 1 2
D 3 2

Sample Output

10


思路

  • 種類並查集+聯通快
  • 觀察題目發現只要有要求的牧場衝突,答案為0;不衝突則答案為2的cnt次方(cnt為聯通塊數目)
  • 三個並查集,一個存牧場是否被提到,另外兩個種類並查集判斷他們有沒有衝突
  • 第一次寫種類並查集,核心思想:朋友的朋友是朋友,朋友的敵人是敵人,敵人的敵人是朋友

程式碼

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=1000005;
int n,m,ans,fa[3*maxn];
int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
void join(int x,int y){int fx=getfa(x),fy=getfa(y); if(fx!=fy) fa[fy]=fx;}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=3*n;++i)	fa[i]=i;
	for(int i=1;i<=m;++i)
	{
		char a[3]; int x,y; scanf("%s%d%d",&a,&x,&y);
		join(x,y);
		if(a[0]=='S') {
			if(fa[x+n]==fa[y+2*n]||fa[x+2*n]==fa[y+n]){puts("0"); return 0;}
			join(x+n,y+n);
			join(x+2*n,y+2*n);
		}
		else {
			if(fa[x+n]==fa[y+n]){puts("0"); return 0;}
			join(x+2*n,y+n);
			join(x+n,y+2*n);
		}
	}
	for(int i=1;i<=n;++i) if(fa[i]==i) ++ans;
	cout<<'1'; while(ans--) cout<<'0';
	return 0; 
}