//思路,首先将奇数格的1变0,0变1,然后计算每一块的大小,大小即为所需结果
//使用并查集,减少赋值所需的工作量
#include <stdio.h>
typedef struct Block_Node_t{
struct Block_Node_t* root;
int count;
int val;
}block_node;
//获取根节点,并将集合扁平化,提高此后的速度;
const int ROOTPTR_ARRSIZE=10;
block_node* GetNodeRoot(block_node* node){
block_node** root_ptr[ROOTPTR_ARRSIZE];
int c_rootptr=0;
while (node->root!=NULL){
if (c_rootptr>=ROOTPTR_ARRSIZE){
printf("ROOTPTR_ARRSIZE太小!\n");
}
else{
root_ptr[c_rootptr++]=&node->root;
}
node=node->root;
}
int i;
for (i=0;i<c_rootptr-1;++i){
*root_ptr[i]=node;
}
return node;
}
//根据节点获取所在块的节点数
int CountNodeInBlock(block_node* node){
return GetNodeRoot(node)->count;
}
//初始化节点
int InitNode(block_node* node){
node->root=NULL;
node->count=1;
}
//连接节点
int linkNode(block_node* node1,block_node* node2){
if (GetNodeRoot(node1)==GetNodeRoot(node2)) return; //如果两节点已连接,直接返回
int n1=CountNodeInBlock(node1);
int n2=CountNodeInBlock(node2);
GetNodeRoot(node2)->root=GetNodeRoot(node1);
GetNodeRoot(node1)->count=n1+n2;
}
int main(){
int m,n,x,y,i;
//////////////////////////////////////////////////////
//获取数据
////////////////////////////////////////////////
scanf("%d %d",&n,&m);
block_node map[n][n];
for (y=0;y<n;++y){
for (x=0;x<n;++x){
InitNode(&map[y][x]);
scanf("%d",&map[y][x].val);
if ((x+y&1)==1){
map[y][x].val^=1; //使奇数格的值1变0,0变1;
}
}
}
int query[m][2]; //记录询问,主要是为了让结构清晰
for (i=0;i<m;++i){
scanf("%d %d",&query[i][0],&query[i][1]);
}
//////////////////////////////////////////////////////
//遍历,并连接处于同一块的节点
////////////////////////////////////////////////
for (y=0;y<n;++y){
for (x=0;x<n;++x){
if (x+1<n){ //只需要考虑下方和右方的节点,因为左方和上方的节点已经提前遍历了
if (map[y][x].val==map[y][x+1].val){
linkNode(&map[y][x],&map[y][x+1]);
}
}
if (y+1<n){
if (map[y][x].val==map[y+1][x].val){
linkNode(&map[y][x],&map[y+1][x]);
}
}
}
}
for (i=0;i<m;++i){
y=query[i][0]-1;
x=query[i][1]-1;
block_node *node=&map[y][x];
printf("%d\n",CountNodeInBlock(node));
}
}
|