@noi.ac - [email protected] cleaner

目录

  • @[email protected]
  • @[email protected]
  • @accepted [email protected]
  • @[email protected]

@[email protected]

小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。

@[email protected]

不妨看看给定机器人半径为 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 [email protected]

#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);
    }
}

@[email protected]

康复计划 - 1。

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

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

原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/11072195.html

时间: 2024-10-09 14:54:06

@noi.ac - [email protected] cleaner的相关文章

@noi.ac - [email&#160;protected] shuffle

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 给定一个长度为 n 的序列 s1,s2,-,sn,它有 2^n?1 个非空子序列.请对于每个 k=0,1,2,-,n 统计 s 有多少非空子序列 a 经过重排成 b 后,ai = bi 的位置数量的最小可能值恰好为k. input 第一行包含一个正整数 n ,表示序列的长度. 第二行包

@noi.ac - [email&#160;protected] game

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 小 Q 和小 T 正在玩一种双人游戏.m 张木牌从左往右排成一排,第 i 张木牌上写着一个正整数 bi.小 Q 和小 T 轮流行动总计 m 轮,小 Q 先手.在每一轮中,行动方需要选择最左或者最右的一张木牌并将其拿走.游戏最后每个人的得分即为他拿走的木牌上写着的数字之和,得分较大的一方

@noi.ac - [email&#160;protected] 老头子的话

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 老头子是小学校长,小学生(大哥)们都很听老头子的话.一天,老头子给小学生(大哥)们发苹果吃. 一共有 n 个小学生(大哥),老头子每一次会等概率选择一位小学生(大哥)并给他一个苹果.一个小学生(大哥)变得开心当且仅当他拥有的苹果数 ≥k. 因为老头子年纪大了,所以他想要你告诉他,期望多

git clone gi[email&#160;protected]:xxx.git Permission denied (publickey) 问题解决办法

本文主要解决一个问题 git clone 出现公共密钥的权限问题.症状如下: CasondeMacBook-Pro:devops cason$ git clone [email protected]:360yyou/yyou.gitCloning into 'yyou'...Permission denied (publickey).fatal: Could not read from remote repository. Please make sure you have the correc

Xcode连接[email&#160;protected] (oschina git代码托管)

Xcode 已经集成了git,建立新项目时钩选使用git,然后按照下面步骤让Xcode和git@osc 建立连接. 第一步:成生SSH密钥 打开终端命令工具,输入命令:ssh-keygen -t rsa -C "[email protected]" 注意ssh-keygen没有空格.屏幕输出: Generating public/private rsa key pair. Enter file in which to save the key (/Users/diaosi/.ssh/i

使用Mac OS X 终端连接[email&#160;protected]

环境准备: Xcode(直接AppStore下载安装) Git(可以在http://code.google.com/p/git-osx-installer/下载git安装程序,或者在https://www.kernel.org/pub/software/scm/git/下载源码安装.) 源码安装过程: 解压源码包 tar xjvf git-1.8.3.tar.bz2 编译 cd git-1.8.3 ./configure --prefix=/usr/local make 安装 sudo make

GDCPC2016题解 by [email&#160;protected] | Asiimov

Problem A. ABCD 题目大意 给出一个四边形四条边AB.CD.AD.BC及两条对角线AC.BD的长度,问这个四边形的顶点能否在一个圆上 算法思路 通过余弦定理考察∠ACB与∠ADB是否相等即可. 时间复杂度: O(1) 代码 /** * Copyright ? 2016 Authors. All rights reserved. * * FileName: A.cpp * Author: Beiyu Li <[email protected]> * Date: 2016-05-09

@codeforces - [email&#160;protected] Oleg and chess

目录 @description - [email protected] @[email protected] @part - [email protected] @part - [email protected] @part - [email protected] @part - [email protected] @accepted [email protected] @[email protected] @description - [email protected] 给定一个 n*n 的棋

@hdu - [email&#160;protected] Counting Stars

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 给定一个 n 点 m 边的无向图(无重边自环),求有多少子图形如,包含 4 个点 {A, B, C, D} 与 6 条边 {AB, BC, CD, DA, AC}. 原题链接. @[email protected] 一个并不常用的黑科技:三元环计数. mark一下博客地址. 注意到题目