NBOJ 1187 Hole Breaker 并查集

题目来源:http://ac.nbutoj.com/Problem/view.xhtml?id=1187

题意:就是说有一个方阵,然后对小方阵操作,也就是标记小方阵,求最后标记的方阵中能连到一起的方阵最大是多少。能连到一起的条件是至少有一条公共边。

思路:由于有多次询问,每次询问都要输出,做多询问200000次,因此朴素方法的话,肯定会tle。由此想到并查集,对小方阵标记时,查看该小方阵的四周是否有标记的,若有标记的,则用并查集合并到一个集合里面即可。

代码:

#include <iostream>
#include <cstdio>
#include <string.h>
#include <string>
using namespace std;

#define CLR(arr,val) memset(arr,val,sizeof(arr))
const int N = 1001000;
int father[N],num[N],flag[N],mmax;
int find(int x){
	int fx = father[x];
	if(fx == x) return father[x];
	else{
	  father[x] = find(father[x]);
	  return father[x];
	}
}
void Unionset(int dit,int value){
	int fdit = find(dit);
	int fvalue = find(value);
	if(fdit != fvalue){
	  father[fvalue] = fdit;
	  num[fdit] += num[fvalue];
	  if(num[fdit] > mmax)
	     mmax = num[fdit];
	}
	return;
}
int main(){
	//freopen("1.txt","r",stdin);
	int n,ask;
	while(scanf("%d",&n) != EOF){
	  scanf("%d",&ask);
	  char ss[3];
	  for(int i = 0;i < n*n;++i){
		  father[i] = i;
		  num[i] = 1;
	  }
	  int x,y,up,down,left,right,dit,isnot = 0;
	  CLR(flag,0);
	  mmax = 0;
	  while(ask--){
	    scanf("%s",ss);
		if(ss[0] == 'B'){
		  isnot = 1;
		  scanf("%d%d",&x,&y);
		  if(x == 0) dit = y;
		  else dit = x*n+y;
		  flag[dit] = 1;
		  if(x != n-1 && flag[dit+n])
			  Unionset(dit,dit+n);
		  if(x != 0 && flag[dit-n])
			  Unionset(dit,dit-n);
		  if(y != 0 && flag[dit-1])
			  Unionset(dit,dit-1);
		  if(y != n-1 && flag[dit+1])
			  Unionset(dit,dit+1);
		}
		else{
			 if(mmax == 0 && isnot == 1)
				 printf("1\n");
			 else
			    printf("%d\n",mmax);
		}
	  }
	}
	return 0;
}


你可能感兴趣的:(NBOJ 1187 Hole Breaker 并查集)