[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了。
#include<queue>
#include<vector>
#include<cstdio>
#include<cctype>
#include<algorithm> inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
inline bool isMasu(const char &ch) {
return ch=='.'||ch=='#';
}
inline char getmasu() {
register char ch;
while(!isMasu(ch=getchar()));
return ch;
} const int inf=0x7fffffff;
const int dx[]={,-,,},dy[]={,,,-};
const int H=,W=,P=,logP=,Q=; int h,w,p;
int map[H][W]={{}}; class DisjointSet {
private:
int anc[P];
int find(const int &x) {
return x==anc[x]?x:anc[x]=find(anc[x]);
}
public:
DisjointSet() {
for(register int i=;i<P;i++) {
anc[i]=i;
}
}
void Union(const int &x,const int &y) {
anc[find(x)]=find(y);
}
bool isConnected(const int &x,const int &y) {
return find(x)==find(y);
}
};
DisjointSet s; struct Edge1 {
int u,v,w;
bool operator < (const Edge1 &another) const {
return w<another.w;
}
};
std::vector<Edge1> e1; struct Edge {
int to,w;
};
std::vector<Edge> e[P];
inline void add_edge(const int &u,const int &v,const int &w) {
e[u].push_back((Edge){v,w});
} struct State {
int dis,root;
};
State vis[H][W]; struct Point {
int x,y;
bool onMap() const {
return x&&y&&x<=h&&y<=w;
}
};
std::queue<Point> q; inline void bfs() {
for(register int i=;i<=h;i++) {
for(register int j=;j<=w;j++) {
if(map[i][j]>) {
q.push((Point){i,j});
vis[i][j]=(State){,map[i][j]};
} else {
vis[i][j]=(State){-,};
}
}
}
while(!q.empty()) {
const Point a=q.front();
q.pop();
for(register int i=;i<;i++) {
Point b=(Point){a.x+dx[i],a.y+dy[i]};
if(!b.onMap()) continue;
if(!~map[b.x][b.y]) continue;
if(vis[b.x][b.y].root) {
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;
if(u==v) continue;
e1.push_back((Edge1){u,v,w});
} else {
vis[b.x][b.y]=(State){vis[a.x][a.y].dis+,vis[a.x][a.y].root};
q.push((Point){b.x,b.y});
}
}
}
} inline void kruskal() {
std::sort(e1.begin(),e1.end());
for(register std::vector<Edge1>::iterator i=e1.begin();i!=e1.end();i++) {
const int &u=i->u,&v=i->v,&w=i->w;
if(s.isConnected(u,v)) continue;
s.Union(u,v);
add_edge(u,v,w);
add_edge(v,u,w);
}
e1.clear();
} class SparseTable {
private:
int dep[P];
int anc[P][logP],max[P][logP];
int log2(const float &x) const {
return ((unsigned&)x>>&)-;
}
void dfs(const int &x) {
dep[x]=dep[anc[x][]]+;
for(int i=;i<=log2(dep[x]);i++) {
anc[x][i]=anc[anc[x][i-]][i-];
max[x][i]=std::max(max[x][i-],max[anc[x][i-]][i-]);
}
for(std::vector<Edge>::iterator i=e[x].begin();i!=e[x].end();i++) {
const int &y=i->to;
if(y==anc[x][]) continue;
anc[y][]=x;
max[y][]=i->w;
dfs(y);
}
e[x].clear();
}
public:
void init() {
for(register int i=;i<=p;i++) {
if(!dep[i]) {
dfs(i);
}
}
}
int query(int x,int y) const {
if(!s.isConnected(x,y)) return -;
int ret=;
while(dep[x]!=dep[y]) {
if(dep[x]<dep[y]) {
std::swap(x,y);
}
for(register int i=log2(dep[x]);i>=;i--) {
if(dep[anc[x][i]]>=dep[y]) {
ret=std::max(ret,max[x][i]);
x=anc[x][i];
}
}
}
if(x==y) return ret;
for(register int i=log2(dep[x]);i>=;i--) {
if(anc[x][i]!=anc[y][i]) {
ret=std::max(ret,std::max(max[x][i],max[y][i]));
x=anc[x][i],y=anc[y][i];
}
}
ret=std::max(ret,std::max(max[x][],max[y][]));
return ret;
}
};
SparseTable t; int main() {
h=getint(),w=getint(),p=getint();
const int q=getint();
for(register int i=;i<=h;i++) {
for(register int j=;j<=w;j++) {
if(getmasu()=='#') map[i][j]=-;
}
}
for(register int i=;i<=p;i++) {
const int x=getint(),y=getint();
map[x][y]=i;
}
bfs();
kruskal();
t.init();
for(register int i=;i<q;i++) {
printf("%d\n",t.query(getint(),getint()));
}
return ;
}
附官方题解:
[JOISC2014]水筒的更多相关文章
- [JOISC2014]スタンプラリー
[JOISC2014]スタンプラリー 题目大意: 有\(n(n\le3000)\)个车站,另有一个起点站和终点站,所有车站排成一条链,相邻两个车站之间的距离为\(t\).每个车站都有一个上行站台.一个 ...
- [JOISC2014]友だちをつくろう
[JOISC2014]友だちをつくろう 题目大意: 一个\(n(n\le10^5)\)个点,\(m(m\le2\times10^5)\)条边的有向图.对于两个点\(i,j\),如果存在一个点\(k\) ...
- [JOISC2014]ストラップ
[JOISC2014]ストラップ 题目大意: 有\(n(n\le2000)\)个挂饰,每个挂饰有一个喜悦值\(b_i(|b_i|\le10^6)\),下面有\(b_i(b_i\le10^6)\)个挂钩 ...
- [JOISC2014]電圧
[JOISC2014]電圧 题目大意: 一个\(n(n\le10^5)\)个点,\(m(m\le2\times10^5)\)条边的无向图.要在图中找到一条边,满足去掉这条边后,剩下的图是一个二分图,且 ...
- [JOISC2014]バス通学
[JOISC2014]バス通学 题目大意: 有\(n(n\le10^5)\)个点和\(m(m\le3\times10^5)\)条交通线路.第\(i\)条交通线路可以让你在时间\(x_i\)从\(a_i ...
- [JOISC2014]たのしい家庭菜園
[JOISC2014]たのしい家庭菜園 题目大意: 给定一个长度为\(n(n\le3\times10^5)\)的序列\(A(A_i\le10^9)\).只能交换相邻两个数,问最少需要几步可以将它变成一 ...
- [JOISC2014]歴史の研究/[BZOJ4241]历史研究
[JOISC2014]歴史の研究/[BZOJ4241]历史研究 题目大意: 一个长度为\(n(n\le10^5)\)的数列\(A(A_i\le10^9)\),定义一个元素对一个区间\([l,r]\)的 ...
- [BZOJ4237]稻草人/[JOISC2014]かかし
[BZOJ4237]稻草人/[JOISC2014]かかし 题目大意: 平面上\(n(n\le2\times10^5)\)个点,若一个矩形各边与坐标轴平行,左下角和右上角都在\(n\)个点之中,且内部不 ...
- P4138 [JOISC2014]挂饰
P4138 [JOISC2014]挂饰 ◦ N个装在手机上的挂饰.挂饰附有可以挂其他挂件的挂钩.每个挂件要么直接挂在手机上,要么挂在其他挂件的挂钩上.直接挂在手机上的挂件最多有1个. ...
随机推荐
- Struts2笔记3--获取ServletAPI和OGNL与值栈
获取ServletAPI: 第一种方式: //在request域中放入属性req,暂且认为getContext()获取的是request域空间,但实际不是 ActionContext.getConte ...
- Oracle数据库中几种常见的SCN
控制文件中的SCN 数据文件头的SCN 数据块中的SCN 日志文件头中的SCN 事务SCN 内存中的SCN 一 控制文件中的SCN 1.1 数据库SCN 数据库SCN表示最近一次全量checkpoin ...
- CentOS6.6中安装telnet
一.查看本机是否安装telnet rpm -qa | grep telnet 如果什么都不显示.说明你没有安装telnet 二.开始安装 yum install xinetd yum install ...
- mysql高可用架构 -> MHA配置VIP漂移-05
VIP漂移的两种方式 1)通过keepalived的方式,管理虚拟IP的漂移 2)通过MHA自带脚本方式,管理虚拟IP的漂移 MHA脚本方式 虚拟ip漂移的脚本下载地址 -> wget http ...
- HTML5 之图片上传预处理
在开发 H5 应用的时候碰到一个问题,应用只需要一张小的缩略图,而用户用手机上传的确是一张大图,手机摄像机拍的图片好几 M,这可要浪费很多流量. 像我这么为用户着想的程序员,绝对不会让这种事情发生的, ...
- 02 Go 1.2 Release Notes
Go 1.2 Release Notes Introduction to Go 1.2 Changes to the language Use of nil Three-index slices Ch ...
- 手淘移动适配方案flexible.js兼容bug处理
什么是flexible.js 移动端自适应方案 https://www.jianshu.com/p/04efb4a1d2f8 什么是rem 这个单位代表根元素的 font-size 大小(例如 元素的 ...
- 拉格朗日(Lagrange)插值算法
拉格朗日插值(Lagrange interpolation)是一种多项式插值方法,指插值条件中不出现被插函数导数值,过n+1个样点,满足如下图的插值条件的多项式.也叫做拉格朗日公式. 这里以拉格朗日 ...
- Visual Studio Code 常用插件整理
常用插件说明: 一.HTML Snippets 超级使用且初级的H5代码片段以及提示 二.HTML CSS Support 让HTML标签上写class智能提示当前项目所支持的样式 三.Debugg ...
- bzoj 1899 贪心+dp
思路:这个贪心排顺序我居然没看出来. 吃饭时间长的在前面, 用反证法很容易得出. 剩下的就是瞎dp啦. #include<bits/stdc++.h> #define LL long lo ...