BZOJ4242 : 水壶

对于任意两个建筑物,以它们之间的最短路为边权求出最小生成树。

则询问(x,y)的答案为最小生成树上x到y路径上边权的最大值。

BFS求出离每个点最近的建筑物以及到它的距离,可以发现只有交界处的边才有用,用这些边求MST即可。

 

#include<cstdio>
#include<algorithm>
using namespace std;
const int L=2010,N=200010,K=17,inf=~0U>>1;
int H,W,n,m,Q,i,j,x,y,z,p,mx;
int dis[L][L][2],q[L*L][2],h=1,t;
int fa[N],g[N],v[N<<1],w[N<<1],nxt[N<<1],ed,f[N][K+1],fm[N][K+1],d[N];
char s[L];bool a[L][L],vis[L][L];
struct E{int x,y;E*nxt;}*e[L*L],pool[L*L],*cur=pool;
inline void up(int&a,int b){if(a<b)a=b;}
inline void bfs(int x,int y,int z,int p){
  if(x<1||x>H||y<1||y>W||vis[x][y]||!a[x][y])return;
  vis[x][y]=1,dis[x][y][0]=z,dis[x][y][1]=p,q[++t][0]=x,q[t][1]=y;
}
inline void check(int a,int b,int c,int d){
  if(vis[a][b]&&vis[c][d]&&dis[a][b][1]!=dis[c][d][1]){
    int x=dis[a][b][0]+dis[c][d][0];
    E*p=cur++;p->x=dis[a][b][1];p->y=dis[c][d][1];p->nxt=e[x];e[x]=p;
    up(mx,x);
  }
}
int F(int x){return fa[x]==x?x:fa[x]=F(fa[x]);}
inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x,int pre,int dis){
  f[x][0]=pre,fm[x][0]=dis;d[x]=d[pre]+1;
  for(int i=1;i<=K;i++)f[x][i]=f[f[x][i-1]][i-1],fm[x][i]=max(fm[x][i-1],fm[f[x][i-1]][i-1]);
  for(int i=g[x];i;i=nxt[i])if(v[i]!=pre)dfs(v[i],x,w[i]);
}
inline int ask(int x,int y){
  if(F(x)!=F(y))return -1;
  int t=0,i;
  if(d[x]<d[y])swap(x,y);
  for(i=K;~i;i--)if(d[f[x][i]]>=d[y])up(t,fm[x][i]),x=f[x][i];
  if(x==y)return t;
  for(i=K;~i;i--)if(f[x][i]!=f[y][i])up(t,max(fm[x][i],fm[y][i])),x=f[x][i],y=f[y][i];
  return max(t,max(fm[x][0],fm[y][0]));
}
inline void read(int&a){char ch;while(!(((ch=getchar())>='0')&&(ch<='9')));a=ch-'0';while(((ch=getchar())>='0')&&(ch<='9'))(a*=10)+=ch-'0';}
int main(){
  read(H),read(W),read(n),read(Q);
  for(i=1;i<=H;i++)for(scanf("%s",s+1),j=1;j<=W;j++)a[i][j]=s[j]=='.';
  for(i=1;i<=n;i++)read(x),read(y),bfs(x,y,0,i),fa[i]=i;
  while(h<=t){
    x=q[h][0],y=q[h++][1],z=dis[x][y][0]+1,p=dis[x][y][1];
    bfs(x-1,y,z,p),bfs(x+1,y,z,p),bfs(x,y-1,z,p),bfs(x,y+1,z,p);
  }
  for(i=1;i<=H;i++)for(j=1;j<W;j++)check(i,j,i,j+1);
  for(i=1;i<H;i++)for(j=1;j<=W;j++)check(i,j,i+1,j);
  for(i=0;i<=mx;i++)for(E*p=e[i];p;p=p->nxt)if(F(p->x)!=F(p->y))add(p->x,p->y,i),add(p->y,p->x,i),fa[fa[p->x]]=fa[p->y];
  for(i=1;i<=n;i++)if(!d[i])dfs(i,0,0);
  while(Q--)read(x),read(y),printf("%d\n",ask(x,y));
  return 0;
}

  

posted @ 2015-08-19 02:12  Claris  阅读(519)  评论(0编辑  收藏  举报