[JOISC2014]水筒
OJ题号:
BZOJ4242、AtCoder-JOISC2014E
题目大意:
给你一个h*w的网格图,每个格子可能是空地、障碍物和建筑物。
你只可以从空地上走过或者从建筑物中穿过。
建筑物总共有p个,现在有q组询问,求从建筑物A到建筑物B的过程中在空地上连续走过的最长一段路最短能是多少。
思路:
为了保证走过的最长路最短,我们可以对所有的建筑物及其路径构造最小生成树。
正确性显然:为了保证最长路最短,我们要使所有能走的边尽量小,这实际上就是一个贪心,也就是我们所熟知的Kruskal算法。
题目并没有告诉你总共有哪些边,而原图又是一个网格图,暴力算出所有的边显然会TLE,因此需要考虑如何将所有可能边算出来。
我们可以对原图进行BFS,首先将所有的建筑物加入到队列中,然后对每个建筑物向外扩展。
如果当两个建筑物所扩展到的范围出现重叠时,我们就将经由该格点的连接两个建筑物的路径加入边集。
如果两个建筑物最后扩展到的范围被其它建筑物的范围所阻断,不能直接相连,那么说明这两个点可以经由另一个点中转达到更优。
然而两个建筑物可能会重叠好几次,这时候并不一定要判重,因为每个格点上最多会被连4条边,整个图就最多有h*w*4条边,事实上远远达不到这个值。
实践证明用map判重反而比不判重要慢。
每次还要特判重叠的范围是不是属于同一个建筑物,不然会多加很多边,还会MLE。
然后跑一遍Kruskal求最小生成树即可。
最后的询问就相当于树上RMQ,用稀疏表或者树剖之类的数据结构维护一下即可。
然后交到AtCoder上随随便便拿了Rank1,吊打yutaka1999。
交到BZOJ上无限RE。
不放心,觉得是系统环境的问题,用Ubuntu测了一发,还是AC。
找管理员要数据被告知就是官方数据。
把C++流读入改成C标准读入就A了。
1 #include<queue> 2 #include<vector> 3 #include<cstdio> 4 #include<cctype> 5 #include<algorithm> 6 7 inline int getint() { 8 register char ch; 9 while(!isdigit(ch=getchar())); 10 register int x=ch^'0'; 11 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 12 return x; 13 } 14 inline bool isMasu(const char &ch) { 15 return ch=='.'||ch=='#'; 16 } 17 inline char getmasu() { 18 register char ch; 19 while(!isMasu(ch=getchar())); 20 return ch; 21 } 22 23 const int inf=0x7fffffff; 24 const int dx[]={1,-1,0,0},dy[]={0,0,1,-1}; 25 const int H=2001,W=2001,P=200001,logP=18,Q=200001; 26 27 int h,w,p; 28 int map[H][W]={{0}}; 29 30 class DisjointSet { 31 private: 32 int anc[P]; 33 int find(const int &x) { 34 return x==anc[x]?x:anc[x]=find(anc[x]); 35 } 36 public: 37 DisjointSet() { 38 for(register int i=0;i<P;i++) { 39 anc[i]=i; 40 } 41 } 42 void Union(const int &x,const int &y) { 43 anc[find(x)]=find(y); 44 } 45 bool isConnected(const int &x,const int &y) { 46 return find(x)==find(y); 47 } 48 }; 49 DisjointSet s; 50 51 struct Edge1 { 52 int u,v,w; 53 bool operator < (const Edge1 &another) const { 54 return w<another.w; 55 } 56 }; 57 std::vector<Edge1> e1; 58 59 struct Edge { 60 int to,w; 61 }; 62 std::vector<Edge> e[P]; 63 inline void add_edge(const int &u,const int &v,const int &w) { 64 e[u].push_back((Edge){v,w}); 65 } 66 67 struct State { 68 int dis,root; 69 }; 70 State vis[H][W]; 71 72 struct Point { 73 int x,y; 74 bool onMap() const { 75 return x&&y&&x<=h&&y<=w; 76 } 77 }; 78 std::queue<Point> q; 79 80 inline void bfs() { 81 for(register int i=1;i<=h;i++) { 82 for(register int j=1;j<=w;j++) { 83 if(map[i][j]>0) { 84 q.push((Point){i,j}); 85 vis[i][j]=(State){0,map[i][j]}; 86 } else { 87 vis[i][j]=(State){-1,0}; 88 } 89 } 90 } 91 while(!q.empty()) { 92 const Point a=q.front(); 93 q.pop(); 94 for(register int i=0;i<4;i++) { 95 Point b=(Point){a.x+dx[i],a.y+dy[i]}; 96 if(!b.onMap()) continue; 97 if(!~map[b.x][b.y]) continue; 98 if(vis[b.x][b.y].root) { 99 const int &u=vis[a.x][a.y].root,&v=vis[b.x][b.y].root,w=vis[a.x][a.y].dis+vis[b.x][b.y].dis; 100 if(u==v) continue; 101 e1.push_back((Edge1){u,v,w}); 102 } else { 103 vis[b.x][b.y]=(State){vis[a.x][a.y].dis+1,vis[a.x][a.y].root}; 104 q.push((Point){b.x,b.y}); 105 } 106 } 107 } 108 } 109 110 inline void kruskal() { 111 std::sort(e1.begin(),e1.end()); 112 for(register std::vector<Edge1>::iterator i=e1.begin();i!=e1.end();i++) { 113 const int &u=i->u,&v=i->v,&w=i->w; 114 if(s.isConnected(u,v)) continue; 115 s.Union(u,v); 116 add_edge(u,v,w); 117 add_edge(v,u,w); 118 } 119 e1.clear(); 120 } 121 122 class SparseTable { 123 private: 124 int dep[P]; 125 int anc[P][logP],max[P][logP]; 126 int log2(const float &x) const { 127 return ((unsigned&)x>>23&255)-127; 128 } 129 void dfs(const int &x) { 130 dep[x]=dep[anc[x][0]]+1; 131 for(int i=1;i<=log2(dep[x]);i++) { 132 anc[x][i]=anc[anc[x][i-1]][i-1]; 133 max[x][i]=std::max(max[x][i-1],max[anc[x][i-1]][i-1]); 134 } 135 for(std::vector<Edge>::iterator i=e[x].begin();i!=e[x].end();i++) { 136 const int &y=i->to; 137 if(y==anc[x][0]) continue; 138 anc[y][0]=x; 139 max[y][0]=i->w; 140 dfs(y); 141 } 142 e[x].clear(); 143 } 144 public: 145 void init() { 146 for(register int i=1;i<=p;i++) { 147 if(!dep[i]) { 148 dfs(i); 149 } 150 } 151 } 152 int query(int x,int y) const { 153 if(!s.isConnected(x,y)) return -1; 154 int ret=0; 155 while(dep[x]!=dep[y]) { 156 if(dep[x]<dep[y]) { 157 std::swap(x,y); 158 } 159 for(register int i=log2(dep[x]);i>=0;i--) { 160 if(dep[anc[x][i]]>=dep[y]) { 161 ret=std::max(ret,max[x][i]); 162 x=anc[x][i]; 163 } 164 } 165 } 166 if(x==y) return ret; 167 for(register int i=log2(dep[x]);i>=0;i--) { 168 if(anc[x][i]!=anc[y][i]) { 169 ret=std::max(ret,std::max(max[x][i],max[y][i])); 170 x=anc[x][i],y=anc[y][i]; 171 } 172 } 173 ret=std::max(ret,std::max(max[x][0],max[y][0])); 174 return ret; 175 } 176 }; 177 SparseTable t; 178 179 int main() { 180 h=getint(),w=getint(),p=getint(); 181 const int q=getint(); 182 for(register int i=1;i<=h;i++) { 183 for(register int j=1;j<=w;j++) { 184 if(getmasu()=='#') map[i][j]=-1; 185 } 186 } 187 for(register int i=1;i<=p;i++) { 188 const int x=getint(),y=getint(); 189 map[x][y]=i; 190 } 191 bfs(); 192 kruskal(); 193 t.init(); 194 for(register int i=0;i<q;i++) { 195 printf("%d\n",t.query(getint(),getint())); 196 } 197 return 0; 198 }
附官方题解: