2018.11.04 NOIP训练 小水塘(并查集)
程序员文章站
2022-03-03 11:34:36
...
传送门
这是复习普及组的时候做过的题了。
之前一直觉得很难码没有去做。
现在发现可以用并查集直接水过去。
其实就是把题目中说的连通的部分的面积用带权并查集维护一下就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
const int N=105;
const double Big=1.214601836602552,Small=0.785398163397;
int n,m,stat[N][N],fa[N*N*4+5],id[N<<1][N<<1];
double siz[N*N*4+N];
char s[N];
inline int find(int x){return x==fa[x]?fa[x]:fa[x]=find(fa[x]);}
inline int idx(int a,int b,int c){return ((a-1)*m+b)*4+c;}
inline void merge(int a1,int b1,int c1,int a2,int b2,int c2){
if(!a1||!b1||!a2||!b2||a1>n||a2>n||b1>m||b2>m)return;
int fx=find(idx(a1,b1,c1)),fy=find(idx(a2,b2,c2));
if(fx^fy)fa[fx]=fy,siz[fy]+=siz[fx];
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;++i){
scanf("%s",s+1);
for(int j=1;j<=m;++j){
stat[i][j]=s[j]^48;
for(int k=1;k<=4;++k)fa[idx(i,j,k)]=idx(i,j,k);
}
}
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if(!stat[i][j]){
siz[idx(i,j,1)]=siz[idx(i,j,4)]=Small;
siz[idx(i,j,2)]=siz[idx(i,j,3)]=Big;
merge(i,j,2,i,j,3);
}
else{
siz[idx(i,j,1)]=siz[idx(i,j,4)]=Big;
siz[idx(i,j,2)]=siz[idx(i,j,3)]=Small;
merge(i,j,1,i,j,4);
}
merge(i,j,1,i-1,j,3),merge(i,j,2,i-1,j,4);
merge(i,j,1,i,j-1,2),merge(i,j,3,i,j-1,4);
id[(i-1)<<1][(j-1)<<1]=idx(i,j,1);
id[(i-1)<<1][j<<1]=idx(i,j,2);
id[i<<1][(j-1)<<1]=idx(i,j,3);
id[i<<1][j<<1]=idx(i,j,4);
id[(i<<1)-1][(j<<1)-1]=idx(i,j,stat[i][j]+3);
}
}
for(int i=read(),x,y;i;--i)x=read(),y=read(),printf("%.4lf\n",(x+y)&1?0.000:siz[find(id[x][y])]);
return 0;
}
上一篇: 连续和和下标系列问题
下一篇: 图的遍历(DFS)