@description@

小Q计划在自己的新家中购置一台圆形的扫地机器人。小Q的家中有一个宽度为 m 的走廊,走廊很长,如果将这个走廊的俯视图画在平面直角坐标系上的话,那么走廊的两堵墙可以分别看作直线 y=0 和直线 y=m,两堵墙之间的部分代表走廊。

小Q会按照顺序依次在走廊中安置 n 个家具。第 i 个家具的位置为 (xi,yi),宽度可以忽略不计,同一个位置可能会有多个家具。

在商店中,扫地机器人的半径只能是整数。请找到最大可能的整数半径 R,使得以 R 为半径的扫地机器人可以从走廊的最左侧到达最右侧,扫地机器人不可以穿过家具或者墙壁,但是允许接触它们。

请写一个程序,帮助小 Q 在每次安置下新的家具后,都能计算出这个条件下允许通过的扫地机器人的最大可能半径。

input

第一行包含两个正整数 n, m,分别表示家具的数量和走廊的宽度。

接下来 n 行,每行两个正整数 xi, yi,表示第 i 个被安置下的家具的位置。

output

输出 n 行,每行输出一个整数,第 i 行输出在安置下前 i 个家具后,扫地机器人的半径的最大可能值。

sample input

5 6

1 2

3 2

2 1

1 3

4 5

sample output

2

2

2

1

1

对于 100% 的数据:1≤xi≤109,1≤yi<m≤109,n≤2500。

@solution@

不妨看看给定机器人半径为 r0 的情况下会发生什么。

我们可以以障碍为圆心,画出一个半径为 r0 的禁行区域(即:机器人的圆心不能经过这个区域)。

同时也可以以两面墙画出相应的禁行区域。

此时如果禁行区域将两面墙连接在一起,该半径 r0 不合法。

稍微转换一下:

如果半径 x 是使得障碍/墙 a, b 所对应的禁行区域连接(即有交集)的最小整数半径,我们就在 a, b 之间连一条边权为 x 的边。

当半径为 r0 的时候,如果存在一条两面墙之间的路径,使得路径上的每一条边的边权 <= r0,则 r0 不合法。

等价于路径上的最大边权 <= r0。

题目要求的是最大合法的整数半径 R,但我们可以将问题做一个简单的转换:找到最小不合法的整数半径 R'。

因为是整数,所以可以得到 R = R' - 1。

问题最终可以转换为:找到两墙之间的一条路径,使这条路径上的最大值最小。

这是一个典型的最小生成树应用。

怎么动态维护最小生成树呢?

一开始我原本想的是用 lct 来搞,看了题解才发现:

woc 它只需要求 O(n) 次最小生成树,所以没必要每个时刻的最小生成树都求解出来。

于是:每次加入一个新的障碍,增加 O(n) 条边,与上个时刻的最小生成树一起(也是 O(n) 条边)求解最小生成树。

跑 kruskal 即可。所以总的复杂度是优秀的 O(n^2log n)。

@accepted code@

#include<cmath>
#include<vector>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 2500 + 10;
const ll INF = (1LL<<60);
struct edge{
int u, v; ll d;
edge(int _u=0, int _v=0, ll _d=0):u(_u), v(_v), d(_d){}
friend bool operator < (edge a, edge b) {return a.d < b.d;}
}edges[2*MAXN];
int fa[MAXN];
int find(int x) {
return fa[x] = (fa[x] == x) ? x : find(fa[x]);
}
ll m, x[MAXN], y[MAXN]; int n;
ll dist(int i, int j) {
return ll(sqrt((x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j])));
}
vector<pair<int, ll> >G[MAXN];
void addedge(int u, int v, ll d) {
G[u].push_back(make_pair(v, d));
G[v].push_back(make_pair(u, d));
}
void dfs(int x, int f, ll d) {
if( x == n + 2 ) {
printf("%lld\n", d - 1);
return ;
}
for(int i=0;i<G[x].size();i++)
if( G[x][i].first != f )
dfs(G[x][i].first, x, max(d, G[x][i].second));
}
int main() {
scanf("%d%lld", &n, &m);
edges[1] = edge(n + 1, n + 2, m/2 + 1);
for(int i=1;i<=n;i++) {
scanf("%lld%lld", &x[i], &y[i]);
for(int j=1;j<i;j++)
edges[i+j] = edge(i, j, dist(i, j)/2 + 1);
edges[2*i] = edge(i, n + 1, y[i]/2 + 1);
edges[2*i+1] = edge(i, n + 2, (m - y[i])/2 + 1);
sort(edges + 1, edges + 2*i + 2);
for(int j=1;j<=n+2;j++)
fa[j] = j, G[j].clear();
int cnt = 0;
for(int j=1;j<=2*i+1;j++) {
if( find(edges[j].u) != find(edges[j].v) ) {
fa[find(edges[j].u)] = find(edges[j].v);
edges[++cnt] = edges[j];
}
}
for(int j=1;j<i+2;j++)
addedge(edges[j].u, edges[j].v, edges[j].d);
dfs(n + 1, -1, -INF);
}
}

@details@

康复计划 - 1。

还好。没有什么大的问题。我能记得最小生成树有这个经典应用感觉已经很奇迹了。

只是看题解之前差点就要写 lct 了。

@noi.ac - 488@ cleaner的更多相关文章

  1. # NOI.AC省选赛 第五场T1 子集,与&最大值

    NOI.AC省选赛 第五场T1 A. Mas的童年 题目链接 http://noi.ac/problem/309 思路 0x00 \(n^2\)的暴力挺简单的. ans=max(ans,xor[j-1 ...

  2. NOI.ac #31 MST DP、哈希

    题目传送门:http://noi.ac/problem/31 一道思路好题考虑模拟$Kruskal$的加边方式,然后能够发现非最小生成树边只能在一个已经由边权更小的边连成的连通块中,而树边一定会让两个 ...

  3. NOI.AC NOIP模拟赛 第五场 游记

    NOI.AC NOIP模拟赛 第五场 游记 count 题目大意: 长度为\(n+1(n\le10^5)\)的序列\(A\),其中的每个数都是不大于\(n\)的正整数,且\(n\)以内每个正整数至少出 ...

  4. NOI.AC NOIP模拟赛 第六场 游记

    NOI.AC NOIP模拟赛 第六场 游记 queen 题目大意: 在一个\(n\times n(n\le10^5)\)的棋盘上,放有\(m(m\le10^5)\)个皇后,其中每一个皇后都可以向上.下 ...

  5. NOI.AC NOIP模拟赛 第二场 补记

    NOI.AC NOIP模拟赛 第二场 补记 palindrome 题目大意: 同[CEOI2017]Palindromic Partitions string 同[TC11326]Impossible ...

  6. NOI.AC NOIP模拟赛 第一场 补记

    NOI.AC NOIP模拟赛 第一场 补记 candy 题目大意: 有两个超市,每个超市有\(n(n\le10^5)\)个糖,每个糖\(W\)元.每颗糖有一个愉悦度,其中,第一家商店中的第\(i\)颗 ...

  7. NOI.AC NOIP模拟赛 第四场 补记

    NOI.AC NOIP模拟赛 第四场 补记 子图 题目大意: 一张\(n(n\le5\times10^5)\)个点,\(m(m\le5\times10^5)\)条边的无向图.删去第\(i\)条边需要\ ...

  8. NOI.AC NOIP模拟赛 第三场 补记

    NOI.AC NOIP模拟赛 第三场 补记 列队 题目大意: 给定一个\(n\times m(n,m\le1000)\)的矩阵,每个格子上有一个数\(w_{i,j}\).保证\(w_{i,j}\)互不 ...

  9. NOI.AC WC模拟赛

    4C(容斥) http://noi.ac/contest/56/problem/25 同时交换一行或一列对答案显然没有影响,于是将行列均从大到小排序,每次处理限制相同的一段行列(呈一个L形). 问题变 ...

随机推荐

  1. Python3数据分析与挖掘建模实战

    Python3数据分析与挖掘建模实战  整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受,单论单个知识点课程本身没问题,大家看的时 ...

  2. 【python之路13】python的深浅拷贝

    深浅拷贝 一.数字和字符串 对于 数字 和 字符串 而言,赋值.浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 impor ...

  3. RabbitMQ的优劣势

    优势:支持集群化.高可用部署架构.消息高可靠支持 复杂系统的解耦: 复杂链路的异步调用 瞬时高峰的削峰处理. 这里提一下RocketMQ,是阿里开源的,经过阿里的生产环境的超高并发.高吞吐的考验.性能 ...

  4. Python结合OpenCV学习资料

    1.sunny2038的专栏  http://blog.csdn.net/sunny2038 作者建立了一个学习系列.讲得非常具体,有非常多的主要的图像处理实例. 2. https://github. ...

  5. java 3类的继承

    模板类 泛型程序设计方法 类的组合 类的继承 java只有单继承 隐藏和覆盖 用super.x调用 访问静态属性 静态属性不继承 静态成员只有一个,不会有副本 静态成员只有一个所有的超类和子类 方法的 ...

  6. iOS自动化打包上传的踩坑记

    http://www.cocoachina.com/ios/20160624/16811.html 很久以前就看了很多关于iOS自动打包ipa的文章, 看着感觉很简单, 但是因为一直没有AppleDe ...

  7. python中几种单例模式的实现

    单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...

  8. pytest fixture 利用 params参数实现用例集合

    @pytest.fixture有一个params参数,接受一个列表,列表中每个数据都可以作为用例的输入.也就说有多少数据,就会形成多少用例.如下面例子,就形成3条用例 test_parametrizi ...

  9. Linux 内存管理之mmap详解

    找了好多,最后发现下面这篇时讲的比较通俗易懂的. Linux内存管理之mmap详解-heavent2010-ChinaUnix博客 http://blog.chinaunix.net/uid-2666 ...

  10. Spring_使用(JDBC)

    Spring_对JDBC的支持 使用JdbcTemplate更新数据库 导入jar包 创建applicationcontext.xml <?xml version="1.0" ...