「APIO2018选圆圈」

题目描述

在平面上,有 \(n\) 个圆,记为 \(c_1, c_2, \ldots, c_n\) 。我们尝试对这些圆运行这个算法:

  1. 找到这些圆中半径最大的。如果有多个半径最大的圆,选择编号最小的。记为 \(c_i\) 。
  2. 删除 \(c_i\) 及与其有交集的所有圆。两个圆有交集当且仅当平面上存在一个点,这个点同时在这两个圆的圆周上或圆内。
  3. 重复上面两个步骤直到所有的圆都被删除。

当 \(c_i\) 被删除时,若循环中第1步选择的圆是 \(c_j\) ,我们说 \(c_i\) 被 \(c_j\) 删除。对于每个圆,求出它是被哪一个圆删除的。

解题思路 :

越抓越痒有理想,\(n^2\) 有信仰。

首先把圆心拿出来建KD树,对于每一棵子树,维护出一个矩形框住这些圆的并,每次删除爆枚整棵树通过判断和这个矩形有没有交来剪枝,最坏复杂度 \(O(n^2)\) ,好像旋转某个角度就卡不掉了。

话说写APIO题卡评测真是爽啊,顺便写篇博客存个KD树板子。

/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int f = 0, ch = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = 600005;
const double sina = sqrt(2)/2, cosa = sina, eps = 5e-2; int ans[N], Sgn, rt, n; inline double sqr(double x){ return x * x; }
inline void chkmax(double &x, double y){ if(y > x) x = y; }
inline void chkmin(double &x, double y){ if(y < x) x = y; }
struct Point{ double x, y, r; int id; } a[N], s[N];
inline bool cmp(Point A, Point B){
if(Sgn == 0) return A.x < B.x;
if(Sgn == 1) return A.y < B.y;
if(Sgn == 2) return A.r == B.r ? (A.id < B.id) : (A.r > B.r);
}
struct Kdtree{
int ch[N][2];
struct Node{
double mx[2], mn[2]; int id;
}T[N];
inline void update(int x){
T[x].mx[0] = a[x].x + a[x].r, T[x].mx[1] = a[x].y + a[x].r;
T[x].mn[0] = a[x].x - a[x].r, T[x].mn[1] = a[x].y - a[x].r;
for(int i = 0; i < 2; i++) if(ch[x][i])
for(int j = 0; j < 2; j++){
chkmax(T[x].mx[j], T[ch[x][i]].mx[j]);
chkmin(T[x].mn[j], T[ch[x][i]].mn[j]);
}
}
inline void build(int &u, int l, int r, int sgn){
if(l > r) return;
int mid = l + r >> 1; u = mid, Sgn = sgn;
nth_element(a + l, a + mid, a + r + 1, cmp);
build(ch[u][0], l, mid - 1, sgn ^ 1);
build(ch[u][1], mid + 1, r, sgn ^ 1), update(u);
}
inline void Delete(int u, Point now){
if(!u || now.x - now.r > T[u].mx[0] || now.x + now.r < T[u].mn[0]
|| now.y - now.r > T[u].mx[1] || now.y + now.r < T[u].mn[1]) return;
if(!ans[a[u].id]){
if(sqr(now.x-a[u].x)+sqr(now.y-a[u].y) <= sqr(now.r+a[u].r) + eps)
ans[a[u].id] = now.id, a[u].x = a[u].y = 0, a[u].r = -inf;
}
Delete(ch[u][0], now), Delete(ch[u][1], now), update(u);
}
}van;
int main(){
read(n);
for(int i = 1, x, y; i <= n; i++){
read(x), read(y), read(a[i].r), a[i].id = i;
a[i].x = (double) x * cosa - y * sina;
a[i].y = (double) x * sina + y * cosa;
}
Sgn = 2, sort(a + 1, a + n + 1, cmp);
for(int i = 1; i <= n; i++) s[i] = a[i];
van.build(rt, 1, n, 0);
for(int i = 1; i <= n; i++)
if(!ans[s[i].id]) van.Delete(rt, s[i]);
for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
return 0;
}

「APIO2018选圆圈」的更多相关文章

  1. 「APIO2018新家」

    「APIO2018新家」 题目描述 五福街是一条笔直的道路,这条道路可以看成一个数轴,街上每个建筑物的坐标都可以用一个整数来表示.小明是一位时光旅行者,他知道在这条街上,在过去现在和未来共有 \(n\ ...

  2. BZOJ5465 APIO2018选圆圈(KD-Tree+堆)

    考虑乱搞,用矩形框圆放KD-Tree上,如果当前删除的圆和矩形有交就递归下去删.为防止被卡,将坐标系旋转一定角度即可.注意eps稍微设大一点,最好开上long double. #include< ...

  3. [BZOJ5465][APIO2018]选圆圈(KD-Tree)

    题意:给你n个圆,每次选择半径最大的,将它和与它相交的圆全部删去,输出每个圆是在哪次被删的. KD树模板题.用一个矩形框住这个圆,就可以直接剪枝了.为了防止被卡可以将点旋转一个角度,为了保险还可以多转 ...

  4. LG4819/BZOJ2438 「中山市选2011」杀人游戏 Tarjan缩点+概率

    问题描述 LG4819 BZOJ2438 题解 发现如果有一些人之间认识关系形成环,只需要问一个人就能把控整个环. \(\mathrm{Tarjan}\)缩点. 缩点之后所有入度为\(0\)的点,必须 ...

  5. LOJ2586 APIO2018 选圆圈

    考前挣扎 KD树好题! 暴力模拟 通过kd树的结构把子树内的圈圈框起来 然后排个序根据圆心距 <= R1+R2来判断是否有交点 然后随便转个角度就可以保持优越的nlgn啦 卡精度差评 必须写ep ...

  6. 【LG4631】[APIO2018]Circle selection 选圆圈

    [LG4631][APIO2018]Circle selection 选圆圈 题面 洛谷 题解 用\(kdt\)乱搞剪枝. 维护每个圆在\(x.y\)轴的坐标范围 相当于维护一个矩形的坐标范围为\([ ...

  7. LOJ #2585. 「APIO2018」新家

    #2585. 「APIO2018」新家 https://loj.ac/problem/2585 分析: 线段树+二分. 首先看怎样数颜色,正常的时候,离线扫一遍右端点,每次只记录最右边的点,然后查询左 ...

  8. 【APIO2018】选圆圈(平面分块 | CDQ分治 | KDT)

    Description 给定平面上的 \(n\) 个圆,用三个参数 \((x, y, R)\) 表示圆心坐标和半径. 每次选取最大的一个尚未被删除的圆删除,并同时删除所有与其相切或相交的圆. 最后输出 ...

  9. Libre 6007 「网络流 24 题」方格取数 / Luogu 2774 方格取数问题 (网络流,最大流)

    Libre 6007 「网络流 24 题」方格取数 / Luogu 2774 方格取数问题 (网络流,最大流) Description 在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从 ...

随机推荐

  1. IO流-文件的写入和读取

    1.文件写入 类: FileWriter继承自Writer(字符流基类之一,另外一个为Reader) 方法: writer(参数); 根据参数可以写入字符.字符数组.字符数组中的一部分.整型.字符串. ...

  2. python模块之StringIO/cStringIO(内存文件)

    1. StringIO/cStringIO是什么 这个模块提供了一个类,这个类的实例就像是一个文件一样可以读写,实际上读写的是一个字符串缓存,也可以称之为内存文件. StringIO和文件对象拥有共同 ...

  3. python作业类Fabric主机管理程序开发(第九周)

    作业需求: 1. 运行程序列出主机组或者主机列表 2. 选择指定主机或主机组 3. 选择让主机或者主机组执行命令或者向其传输文件(上传/下载) 4. 充分使用多线程或多进程 5. 不同主机的用户名密码 ...

  4. 笔记本自开wifi设置

    笔记本自开wifi设置 是这样的有些笔记本他自身就可以放出热点供其他的小伙伴们连接,不用非得去下专门的工具有些笔记本的网卡是自带支持双收发的(这里注意我指的是有些笔记本不是全部) 命令我已经写出来了  ...

  5. Deep Learning基础--各个损失函数的总结与比较

    损失函数(loss function)是用来估量你模型的预测值f(x)与真实值Y的不一致程度,它是一个非负实值函数,通常使用L(Y, f(x))来表示,损失函数越小,模型的鲁棒性就越好.损失函数是经验 ...

  6. c++各种排序的简单实现

    /* 直插排序 */ void InsertSort(vector<int> &arr){ for(int i = 1;i < arr.size();++i){ for(in ...

  7. window server 2008 配置ftp并实现用户隔离

    文件传输协议(FTP)是一个标准的网络协议,用于传输计算机文件从一台主机到另一台主机通过TCP为基础的网络,如互联网. -WIKI百科 好久没更新教程了, 今天更新一下博客,也不知道会不会有人看….本 ...

  8. [ python ] 变量及基础的数据类型

    python2 和 python3 不同的编码方式 python2 默认编码方式是 ascii码 python3 默认编码方式是 utf-8 具体表现为:当 python3 和 python2 在打印 ...

  9. C语言再学习之 setjmp与longjmp

    前不久在阅读Quake3源代码的时候,看到一个陌生的函数:setjmp,一番google和查询后,觉得有必要针对setjmp和longjmp这对函数写一篇blog,总结一下. setjmp和longj ...

  10. UVA 11624 Fire!(两次BFS+记录最小着火时间)

    题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...