1. 程式人生 > 其它 >LOJ #2876. 「JOISC 2014 Day2」水壺

LOJ #2876. 「JOISC 2014 Day2」水壺

題面傳送門
考慮詢問肯定是跑出最小生成樹然後看樹上兩點間的路徑上權值的最大值。
把兩兩之間的邊建出來肯定不行,因為這個是網格圖考慮性質。
如果一個點在兩個點之間,那麼這兩個點的之間的邊不需要建邊。
所以我們考慮處理出一個網格圖上的點最近的關鍵點,這個直接多源bfs就好了。
然後找到一個點,如果它的四周有和它最近關鍵點不一樣的點,那麼就建邊,可以發現邊數最多為\(2NM\)
然後複雜度就是\(O(NM(logN+logM)+QlogP)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N 2000
#define M 200000
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-4)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (m*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
using namespace std;
int n,m,P,K,fa[M+5],Id[N*N+5],X[M+5],Y[M+5],x,y,A[N*N+5],Nx,Ny,D[N*N+5],Sh;char c;
int xp[4]={0,1,0,-1};int yp[4]={1,0,-1,0};I int Getfa(int x){return x^fa[x]?fa[x]=Getfa(fa[x]):x;}struct Ques{int x,y;}tmp;queue<Ques> Q;
struct yyy{int to,w,z;};struct ljb{int head,h[M+5];yyy f[M+5<<1];I void add(int x,int y,int z){f[++head]=(yyy){y,z,h[x]};h[x]=head;}}s;I void con(int x,int y,int z){s.add(x,y,z);s.add(y,x,z);/*printf("%d %d %d\n",x,y,z);*/}
namespace Tree{
	int fa[M+5][20],lg[M+5],W[M+5][20],D[M+5];I void BD(){for(RI i=2;i<=P;i++) lg[i]=lg[i/2]+1;}
	I void Make(int x,int LA){fa[x][0]=LA;D[x]=D[LA]+1;RI i;yyy tmp;for(i=1;fa[x][i-1];i++) fa[x][i]=fa[fa[x][i-1]][i-1],W[x][i]=max(W[x][i-1],W[fa[x][i-1]][i-1]);for(i=s.h[x];i;i=tmp.z) tmp=s.f[i],tmp.to^LA&&(W[tmp.to][0]=tmp.w,Make(tmp.to,x),0);}
	I int Qry(int x,int y){if(Getfa(x)^Getfa(y))return -1;int Ans=0;D[x]<D[y]&&(swap(x,y),0);while(D[x]^D[y]) Ans=max(Ans,W[x][lg[D[x]-D[y]]]),x=fa[x][lg[D[x]-D[y]]];if(x==y) return Ans;for(RI i=lg[D[x]];~i;i--) fa[x][i]^fa[y][i]&&(Ans=max(Ans,max(W[x][i],W[y][i])),x=fa[x][i],y=fa[y][i]);return max(Ans,max(W[x][0],W[y][0]));}
}
struct Edge{int x,y,w;}S[N*N+5<<2];I bool cmp(Edge x,Edge y){return x.w<y.w;}
int main(){
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	RI i,j,h;scanf("%d%d%d%d",&n,&m,&P,&K);for(i=1;i<=n*m;i++){c=Gc();while(c^'.'&&c^'#') c=Gc();A[i]=(c=='#');}
	for(i=1;i<=P;i++) scanf("%d%d",&X[i],&Y[i]),Q.push((Ques){X[i],Y[i]}),Id[d(X[i],Y[i])]=i,fa[i]=i;
	while(!Q.empty())for(tmp=Q.front(),Q.pop(),i=0;i<4;i++){
		Nx=tmp.x+xp[i];Ny=tmp.y+yp[i];if(Nx<1||Ny<1||Nx>n||Ny>m||A[d(Nx,Ny)]) continue;if(!Id[d(Nx,Ny)]){D[d(Nx,Ny)]=D[d(tmp.x,tmp.y)]+1;Id[d(Nx,Ny)]=Id[d(tmp.x,tmp.y)];Q.push((Ques){Nx,Ny});continue;}
	}
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){if(A[d(i,j)])continue;
			for(h=0;h<2;h++){
				Nx=i+xp[h];Ny=j+yp[h];if(Nx<1||Ny<1||Nx>n||Ny>m||A[d(Nx,Ny)]||Id[d(i,j)]==Id[d(Nx,Ny)]) continue;S[++Sh]=(Edge){Id[d(i,j)],Id[d(Nx,Ny)],D[d(i,j)]+D[d(Nx,Ny)]}; 
			}
		}
	}
	sort(S+1,S+Sh+1,cmp);for(i=1;i<=Sh;i++) x=Getfa(S[i].x),y=Getfa(S[i].y),x^y&&(con(S[i].x,S[i].y,S[i].w),fa[x]=y);
	Tree::BD();for(i=1;i<=P;i++) !Tree::D[i]&&(Tree::Make(i,0),0);while(K--) scanf("%d%d",&x,&y),printf("%d\n",Tree::Qry(x,y));
}