「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. 一般处理程序、ASP.NET核心知识(5)

    初窥 1.新建一个一般处理程序 新建一个一般处理程序 2.看看里头的代码 public class MyHandler : IHttpHandler { public void ProcessRequ ...

  2. SurfaceFlinger 讲解

    SurfaceFlinger是Android multimedia的一个部分,在Android 的实现中它是一个service,提供系统 范围内的surface composer功能,它能够将各种应用 ...

  3. 64_p8

    python2-cotyledon-tests-1.6.7-2.fc26.noarch.rpm 12-Feb-2017 10:28 23182 python2-couchdb-1.0-6.fc26.n ...

  4. awk正则匹配nginx日志【原创】

    查看网页访问代码不为200和30x所有行的内容 awk '{if($9!~/200|30*/) print $0}' /app/logs/http_access.log 或 awk '$9!~/200 ...

  5. 杂乱的code

    /*o(n)的堆化方法*/ void myjust(vector<int>& A,int i){ int l=i*2+1; int r=i*2+2; int minn=i; if( ...

  6. java基础2 判断语句:if ... else 语句和 switch 语句

    一.if ... else 判断语句 1.if ... else 判断语句的格式 1.1.格式一 if(判断条件){ 执行不满足条件的语句 } 1.2.格式二 if(判断语句){ 满足条件的语句 }e ...

  7. 写在Web考试后的一点小总结

    在实验室折腾附加题折腾了一个多钟没做出来……晚上回到宿舍决定再试一试,按原来的思路居然行了,目测在实验室的时候什么地方打错字了吧(心在流血) 实现晃过元素后出现跟随鼠标的悬浮窗,只有几行代码给我折腾了 ...

  8. hdu4307

    好题,详细题解在这里http://blog.csdn.net/weiguang_123/article/details/8077385 这里回顾一下: 当i和j都在一个集合里会产生新的收益,是经典题直 ...

  9. 反片语(UVa156)

    题目具体描述见:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=835&a ...

  10. Model Binder

    上面需检测id是否为null 如果未提供id值或id值类型不匹配,则使用默认值.但仍需校验值是否超出范围