bzoj 4242 水壶 (多源最短路+最小生成树+启发式合并)
4242: 水壶
Time Limit: 50 Sec Memory Limit: 512 MBSubmit: 1028 Solved: 261
[Submit][Status][Discuss]
Description
JOI君所居住的IOI市以一年四季都十分炎热著称。
IOI市是一个被分成纵H*横W块区域的长方形,每个区域都是建筑物、原野、墙壁之一。建筑物的区域有P个,编号为1...P。
JOI君只能进入建筑物与原野,而且每次只能走到相邻的区域中,且不能移动到市外。
JOI君因为各种各样的事情,必须在各个建筑物之间往返。虽然建筑物中的冷气设备非常好,但原野上的日光十分强烈,因此在原野上每走过一个区域都需要1单位的水。此外,原野上没有诸如自动售货机、饮水处之类的东西,因此IOI市的市民一般都携带水壶出行。大小为x的水壶最多可以装x单位的水,建筑物里有自来水可以将水壶装满。
由于携带大水壶是一件很困难的事情,因此JOI君决定携带尽量小的水壶移动。因此,为了随时能在建筑物之间移动,请你帮他写一个程序来计算最少需要多大的水壶。
现在给出IOI市的地图和Q个询问,第i个询问(1<=i<=Q)为“在建筑物Si和Ti之间移动,最小需要多大的水壶?”,请你对于每个询问输出对应的答案。
Input
第一行四个空格分隔的整数H,W,P,Q,表示IOI市被分成了纵H*横W块区域,有P个建筑物,Q次询问。
接下来H行,第i行(1<=i<=H)有一个长度为W的字符串,每个字符都是’.’或’#’之一,’.’表示这个位置是建筑物或原野,’#’表示这个位置是墙壁。
接下来P行描述IOI市每个建筑物的位置,第i行(1<=i<=P)有两个空格分隔的整数Ai和Bi,表示第i个建筑物的位置在第Ai行第Bi列。保证这个位置在地图中是’.’
接下来Q行,第i行(1<=i<=Q)有两个空格分隔的整数Si和Ti,表示第i个询问为“在建筑物Si和Ti之间移动,最小需要多大的水壶?”
Output
输出Q行,第i行(1<=i<=Q)一个整数,表示在建筑物Si和Ti之间移动最小需要多大的水壶。
如果无法到达,输出-1。此外,如果不需要经过原野就能到达,输出0。
Sample Input
5 5 4 4
.....
..##.
.#...
..#..
.....
1 1
4 2
3 3
2 5
1 2
2 4
1 3
3 4
.....
..##.
.#...
..#..
.....
1 1
4 2
3 3
2 5
1 2
2 4
1 3
3 4
Sample Output
3
4
4
2
4
4
2
HINT
1<=H<=2000
1<=W<=2000
2<=P<=2*10^5
1<=Q<=2*10^5
1<=Ai<=H(1<=i<=P)
1<=Bi<=W(1<=i<=P)
(Ai,Bi)≠(Aj,Bj)(1<=i<j<=P)
1<=Si<Ti<=P(1<=i<=Q)
跟bzoj4144题一样。。不过由于每条边距离相等,所以我们要把优先队列换成普通队列来减少时间。我实在是口算不出来这个时间是多少,然后一开始优先队列一直过不了。看了人家ac代码是普通队列一改就过了。。。orz。不过时间也是挺极限的46s。反正过啦!
1 #include<bits/stdc++.h> 2 #define clr(x) memset(x,0,sizeof(x)) 3 #define clr_1(x) memset(x,-1,sizeof(x)) 4 #define INF 0x3f3f3f3f 5 #define LL long long 6 #define pb push_back 7 #define mod 1000000007 8 #define ls(i) (i<<1) 9 #define rs(i) (i<<1|1) 10 #define mp make_pair 11 #define fi first 12 #define se second 13 using namespace std; 14 const int N=2e3+10; 15 const int M=2e5+10; 16 typedef pair<int,int> pii; 17 typedef pair<LL,pii> plii; 18 queue<pii> que; 19 int mart[N][N]; 20 char s[N]; 21 LL dis[N][N]; 22 int pre[N][N]; 23 bool vis[N][N]; 24 struct edge 25 { 26 int u,v; 27 LL w; 28 edge(int _u,int _v,LL _w):u(_u),v(_v),w(_w) {} 29 }; 30 vector<edge> e; 31 int dirx[4]={0,0,1,-1},diry[4]={1,-1,0,0}; 32 void dij(int n,int m) 33 { 34 while(!que.empty()) 35 { 36 pii p=que.front(); 37 que.pop(); 38 int x=p.fi; 39 int y=p.se; 40 LL d=dis[x][y]; 41 if(vis[x][y]) continue; 42 vis[x][y]=1; 43 for(int i=0;i<4;i++) 44 { 45 int a=x+dirx[i]; 46 int b=y+diry[i]; 47 if(mart[a][b]) continue; 48 if(!pre[a][b] || dis[a][b]>d+1) 49 { 50 dis[a][b]=d+1; 51 pre[a][b]=pre[x][y]; 52 que.push(mp(a,b)); 53 } 54 else if(pre[a][b]!=pre[x][y]) 55 e.pb(edge(pre[a][b],pre[x][y],dis[x][y]+dis[a][b])); 56 } 57 } 58 } 59 int fa[M],rfa[M]; 60 int rk[M],dep[M]; 61 LL up[M]; 62 bool cmp(edge a,edge b) {return a.w<b.w;} 63 int Find(int u) { return fa[u]==u?u:fa[u]=Find(fa[u]);} 64 void Union(int n) 65 { 66 sort(e.begin(),e.end(),cmp); 67 for(int i=1;i<=n;i++) 68 fa[i]=i,rk[i]=1; 69 int sz=e.size(); 70 for(int i=0;i<sz;i++) 71 { 72 int x=e[i].u; 73 int y=e[i].v; 74 LL w=e[i].w; 75 x=Find(x),y=Find(y); 76 if(x==y) continue; 77 if(rk[x]<rk[y]) swap(x,y); 78 if(rk[x]==rk[y]) rk[x]++; 79 fa[y]=x,rfa[y]=x,up[y]=w; 80 } 81 return ; 82 } 83 void dealdep(int u) 84 { 85 if(Find(u)==u) 86 { 87 dep[u]=1; 88 return ; 89 } 90 dealdep(rfa[u]); 91 dep[u]=dep[rfa[u]]+1; 92 return ; 93 } 94 LL solve(int u,int v) 95 { 96 LL maxn=0; 97 if(Find(u)!=Find(v)) return -1; 98 if(dep[u]<dep[v]) swap(u,v); 99 while(dep[u]>dep[v]) 100 { 101 maxn=max(maxn,up[u]); 102 u=rfa[u]; 103 } 104 while(u!=v) 105 { 106 maxn=max(maxn,up[u]); 107 maxn=max(maxn,up[v]); 108 u=rfa[u],v=rfa[v]; 109 } 110 return maxn; 111 } 112 int main() 113 { 114 int n,m,k,q; 115 scanf("%d%d%d%d",&n,&m,&k,&q); 116 for(int i=1;i<=n;i++) 117 { 118 scanf("%s",s+1); 119 for(int j=1;j<=m;j++) 120 if(s[j]=='.') mart[i][j]=0; 121 else mart[i][j]=1; 122 } 123 for(int i=1;i<=m+1;i++) 124 mart[0][i]=mart[n+1][i]=1; 125 for(int i=1;i<=n+1;i++) 126 mart[i][0]=mart[i][m+1]=1; 127 clr_1(dis); 128 for(int i=1;i<=k;i++) 129 { 130 int u,v; 131 scanf("%d%d",&u,&v); 132 dis[u][v]=0; 133 pre[u][v]=i; 134 que.push(mp(u,v)); 135 } 136 dij(n,m); 137 Union(k); 138 for(int i=1;i<=k;i++) 139 if(!dep[i]) dealdep(i); 140 // for(int i=1;i<=k;i++) 141 // cout<<"pos:"<<pt[i]/m+1<<" "<<pt[i]%m+1<<" blk:"<<Find(pt[i])/m+1<<" "<<Find(pt[i])%m+1<<" fa:"<<rfa[pt[i]]/m+1<<" "<<rfa[pt[i]]%m+1<<" dep:"<<dep[pt[i]]<<" val:"<<up[pt[i]]<<endl; 142 while(q--) 143 { 144 int u,v; 145 scanf("%d%d",&u,&v); 146 printf("%lld\n",solve(u,v)); 147 } 148 return 0; 149 }