目录

  • @description@
  • @solution@
  • @accepted code@
  • @details@


@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≤10^9,1≤yi<m≤10^9,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 了。

转载于:https://www.cnblogs.com/Tiw-Air-OAO/p/11072195.html

@noi.ac - 488@ cleaner相关推荐

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

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

  2. NOI.AC#2007-light【根号分治】

    正题 题目链接:http://noi.ac/problem/2007 题目大意 nnn个格子排成一排,每个格子有一个0/10/10/1和一个颜色.开始每个格子都是000,qqq次操作取反一个颜色的所有 ...

  3. NOI.AC#2139-选择【斜率优化dp,树状数组】

    正题 题目链接:http://noi.ac/problem/2139 题目大意 给出nnn个数字的序列aia_iai​.然后选出一个不降子序列最大化子序列的aia_iai​和减去没有任何一个数被选中的 ...

  4. NOI.AC#2144-子串【SAM,倍增】

    正题 题目链接:http://noi.ac/problem/2144 题目大意 给出一个字符串sss和一个序列aaa.将字符串sss的所有本质不同子串降序排序后,求有多少个区间[l,r][l,r][l ...

  5. NOI.AC#2266-Bacteria【根号分治,倍增】

    正题 题目链接:http://noi.ac/problem/2266 题目大意 给出nnn个点的一棵树,有一些边上有中转站(边长度为222,中间有一个中转站),否则就是边长为111. mmm次询问一个 ...

  6. 野鸡NOI.AC模拟赛【2019.10.26】

    前言 截止至2019.10.2614:222019.10.26\ \ \ \ 14:222019.10.26    14:22 成绩 正题 T1:NOI.AC−T1:NOI.AC-T1:NOI.AC− ...

  7. noi.ac 405 bzoj 4403 序列统计 题解

    博客观赏效果更佳 题意简述 noi.ac再次蒯题,实锤了- 请你求长度在 [ 1 , n ] [1,n] [1,n] 范围内,值域在 [ l , r ] [l,r] [l,r] 范围内的序列中,不下降 ...

  8. noi.ac #543 商店

    我们考虑可并堆维护,从深到浅贪心选取. 用priority_queue启发式合并的话,是60pts: #include<iostream> #include<cstdio> # ...

  9. noi.ac 邀请赛1 By cellur925

    A. array 考场:上来就想暴力,首先第一个子任务肯定没问题,怎么搞都行.然后第二个子任务用个数组记下新修的值就行了.第三个子任务用一下等差数列求和公式帮助求解,每次都重新算(因为每次改变全部元素 ...

最新文章

  1. jquery ajax 省 城市 二级菜单 源码,利用了jquery的ajax实现二级联互动菜单
  2. 06.系统编程-3.进程VS线程比较
  3. 到底什么是P问题,NP问题,NPC问题,NP-hard问题?什么是规约(或约化)?
  4. Nginx基础知识之————日志管理
  5. SSH框架中不为人知的细节(一)
  6. 通过反射写一个通用的设置某个对象的某个属性为指定的值
  7. 一个产品经理的自述:我在腾讯工作的这一年(转)
  8. iOS15仿微信详情二维码支持保存本地相册
  9. 分析linux相关日志文件,Linux日志系统与分析.pdf
  10. python request处理_python requests异常处理
  11. 一个***的自白(续)
  12. 专为《巫师3》打造 次世代RedEngine 3引擎公布
  13. 传播易7月发力 微信大号营销成为前锋
  14. android非线性渐变色,不同区域显示不同的渐变效果
  15. 图傅里叶变换(GFT)
  16. 学习c语言第一步安装软件
  17. 生成镶嵌数据集涉及的一些概念和工具
  18. Linux服务器下oracle数据库启动服务操作步骤
  19. JasperReports配置中文字体
  20. 微信小程序 联想搜索功能的实现

热门文章

  1. 计算机专业多媒体技术学什么,计算机多媒体技术需要学习哪些知识
  2. 拷贝构造函数 c语言中文网,C++对象的复制
  3. 此域的推荐安全级别是“安全级-高”的解决办法
  4. Linux的vx开头的文件,linux文件系统简述
  5. VMware虚拟机NAT模式网络配置图文教程
  6. 坑 之 Tensorflow安装在导入模块时会出现ImportError: DLL load failed: 找不到指定的模块的问题
  7. c++primer 12.3.1文本查询程序
  8. static和不完全类型的一个例子
  9. Mysql 添加字段 修改字段 删除字段
  10. 100的阶乘c语言代码,求10000的阶乘(c语言代码实现)