qduoj598
二維並查集+bfs預處理
要點:
1,將二維轉化爲一維
(1,1) (1,2) (1,3)
(2,1) (2,2) (2,3)
(3,1) (3,2) (3,3)
轉化爲:
1 2 3
4 5 6
7 8 9
計算函數:
int point(int x,int y)
{
return (x-1)*m+y;
}
2,bfs進行預處理:
不用對所有的滿足mp[i][j]=='.'的點進行一次bfs,只需對
mp[i][j]=='.'並且是根結點的點進行一次bfs;
3,每一次‘#’變成‘.’,只需訪問這個點的四周即可。
#include<map>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const int num=5*1e3+10;
struct node
{
int x,y;
node(){};
node(int a,int b)
{
x=a;y=b;
}
};
int dp[num*num];
int pre[num*num];
char mp[num][num];
bool vis[num][num];
int n,m;
int point(int x,int y)
{
return (x-1)*m+y;
}
int fa(int x)
{
if(pre[x]!=x) return pre[x]=fa(pre[x]);
return pre[x];
}
void merge(int s1,int s2)
{
int tx=fa(s1);
int ty=fa(s2);
if(tx!=ty)
{
if(dp[tx]>=dp[ty])
{
dp[tx]+=dp[ty];
pre[ty]=tx;
}
else
{
dp[ty]+=dp[tx];
pre[tx]=ty;
}
}
return ;
}
void bfs(int x,int y,int s)
{
vis[x][y]=1;
int nx[4]={0,0,1,-1};
int ny[4]={1,-1,0,0};
int tx,ty,s2;
node t;
queue<node>q;
q.push(node(x,y));
while(q.size())
{
t=q.front();q.pop();
for(int i=0;i<4;i++)
{
tx=t.x+nx[i];
ty=t.y+ny[i];
if(vis[tx][ty]||tx>n||ty>m||tx<1||ty<1||mp[tx][ty]=='#') continue;
vis[tx][ty]=1;
s2=point(tx,ty);
merge(s,s2);
q.push(node(tx,ty));
}
}
vis[x][y]=0;
return ;
}
void int_i(void)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int t=point(i,j);
pre[t]=t;
if(mp[i][j]=='.')
dp[t]=1;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int t=point(i,j);
if(mp[i][j]=='#'||pre[t]!=t) continue;
bfs(i,j,t);
}
}
return ;
}
int main()
{
scanf("%d%d",&n,&m);
getchar();
for(int i=1;i<=n;i++)
scanf("%s",mp[i]+1);
int_i();
int q,x,y;
int nx[4]={1,-1,0,0};
int ny[4]={0,0,-1,1};
int tx,ty,f;
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&x,&y);
mp[x][y]='.';
int s=point(x,y),s2;
dp[s]=1;
for(int i=0;i<4;i++)
{
tx=x+nx[i];
ty=y+ny[i];
if(tx<1||ty<1||tx>n||ty>m||mp[tx][ty]=='#') continue;
s2=point(tx,ty);
merge(s,s2);
}
f=fa(point(x,y));
printf("%d\n",dp[f]);
}
return 0;
}