【Openjudge】岛屿(并查集)

 题目链接

   此题是并查集。考虑到水位不断上涨,所以将时间倒转。先统计最后一天的联通块个数,每一天浮出水面的块进行计算。复杂度O(玄学)。

   代码如下

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;

short u[5]={0,0,1,0,-1};
short w[5]={0,1,0,-1,0};

int n,m;

inline long long read(){
  long long num=0,f=1;
  char ch=getchar();
  while(!isdigit(ch)){
      if(ch=='-')f=-1;
      ch=getchar();
  }
  while(isdigit(ch)){
      num=num*10+ch-'0';
      ch=getchar();
  }
  return num*f;
}

struct Point{
  short x,y;
  int h;
  bool operator <(const Point &a)const{
     return h
  }
}mp[10000000];
int num;
int Map[3001][3001];
int que[1000000];
int ans[1000000];
int father[10000000];
bool jd[3001][3001];

int find(int x){
  if(father[x]!=x)father[x]=find(father[x]);
  return father[x];
}

inline void Union(int x,int y){
  x=find(x);y=find(y);
  father[y]=x;
}

inline int query(int i,int j){
   return (i-1)*m+j;
}

int main(){
  n=read(),m=read();
  for(int i=1;i<=n*m+1;++i)    father[i]=i;
  int s;
  for(int i=1;i<=n;++i)
  for(int j=1;j<=m;++j){
      s=read();
      mp[++num]=(Point){i,j,s};
      Map[i][j]=s;
  }
  sort(mp+1,mp+num+1);
  int T=read();
  for(int i=1;i<=T;++i)    que[i]=read();
  int cnt=1;
  for(int i=T;i>=1;--i){
      ans[i]=ans[i+1];
      while(mp[cnt].h>que[i]&&cnt<=n*m){
          jd[mp[cnt].x][mp[cnt].y]=1;
          ans[i]++;
          for(int j=1;j<=4;++j){
              short x=mp[cnt].x+u[j];
              short y=mp[cnt].y+w[j];
              if(x>0&&y>0&&x<=n&&y<=m&&Map[x][y]>que[i]&&jd[x][y]&&find(query(x,y))!=find(query(mp[cnt].x,mp[cnt].y))){
                  Union(query(x,y),query(mp[cnt].x,mp[cnt].y));
                  ans[i]--;
              }
          }
          cnt++;
      }
  }
  for(int i=1;i<=T;++i)printf("%d ",ans[i]);
  return 0;
}
原文地址:https://www.cnblogs.com/cellular-automaton/p/7467393.html