【LOJ2586】【APIO2018】选圆圈 CDQ分治 扫描线 平衡树
题目描述
在平面上,有 \(n\) 个圆,记为 \(c_1,c_2,\ldots,c_n\) 。我们尝试对这些圆运行这个算法:
- 找到这些圆中半径最大的。如果有多个半径最大的圆,选择编号最小的。记为 \(c_i\) 。
- 删除 \(c_i\) 及与其有交集的所有圆。两个圆有交集当且仅当平面上存在一个点,这个点同时在这两个圆的圆周上或圆内。(原文直译:如果平面上存在一个点被这两个圆所包含,我们称这两个圆有交集。一个点被一个圆包含,当且仅当它位于圆内或圆周上。)
- 重复上面两个步骤直到所有的圆都被删除。
当 \(c_i\) 被删除时,若循环中第1步选择的圆是 \(c_j\) ,我们说 \(c_i\) 被 \(c_j\) 删除。对于每个圆,求出它是被哪一个圆删除的。
\(n\leq 300000\)
题解
貌似不太好枚举每个圆,找出剩下的和这个圆相交的圆。
那就换一种思路。
枚举每个圆 \(i\),找出第一个与这个圆相交且是作为最大的圆被删掉的圆。
前面的作为最大的圆被删掉的圆肯定是两两不相交的,且半径大于圆 \(c_i\)。
那么我们可以对前面的圆维护扫描线,每个圆和当前的直线 \(x=x_0\) 相交两次,可以用括号表示 。
而且由于这些圆两两不相交,括号相对次序不会变。
由于前面的圆半径都比它大,因此和它有交的圆必然经过 \(x=x_i+r_i\) 或 \(x=x_i-r_i\) 或 \(y=y_i-r_i\) 或 \(y=y_i+r_i\)。
所以我们可以在做扫描线时,查询这四个位置的平衡树上,当前圆的前驱后继。
但是这道题有很多个询问。
那就加上一个CDQ分治咯。
时间复杂度:\(O(n\log^2n)\)
实际上跑的比 k-d tree 还慢很多倍。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<cmath>
#include<functional>
#include<set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void sort(int &a,int &b)
{
if(a>b)
swap(a,b);
}
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
int rd()
{
int s=0,c,b=0;
while(((c=getchar())<'0'||c>'9')&&c!='-');
if(c=='-')
{
c=getchar();
b=1;
}
do
{
s=s*10+c-'0';
}
while((c=getchar())>='0'&&c<='9');
return b?-s:s;
}
void put(int x)
{
if(!x)
{
putchar('0');
return;
}
static int c[20];
int t=0;
while(x)
{
c[++t]=x%10;
x/=10;
}
while(t)
putchar(c[t--]+'0');
}
int upmin(int &a,int b)
{
if(b<a)
{
a=b;
return 1;
}
return 0;
}
int upmax(int &a,int b)
{
if(b>a)
{
a=b;
return 1;
}
return 0;
}
const int N=300010;
const int inf=0x7f7f7f7f;
struct circle
{
ll x,y,r;
int id;
};
struct event
{
ll t;
int op;
int v;
event(){}
event(ll a,int b,int c)
{
t=a;
op=b;
v=c;
}
};
int cmp(circle a,circle b)
{
if(a.r!=b.r)
return a.r>b.r;
return a.id<b.id;
}
int cmp2(event a,event b)
{
return a.t<b.t;
}
int n;
circle a[N];
int ans[N];
int final[N];
int b[N];
int m;
event c[2*N];
set<pii> s;
int inter(int x,int y)
{
return (a[x].x-a[y].x)*(a[x].x-a[y].x)+(a[x].y-a[y].y)*(a[x].y-a[y].y)<=(a[x].r+a[y].r)*(a[x].r+a[y].r);
}
void solve(int l,int r)
{
if(l==r)
{
if(ans[l]==inf)
{
ans[l]=l;
b[l]=1;
}
return;
}
int mid=(l+r)>>1;
solve(l,mid);
m=0;
for(int i=l;i<=mid;i++)
if(b[i])
{
c[++m]=event(3*(a[i].x-a[i].r)-2,1,i);
c[++m]=event(3*(a[i].x+a[i].r),2,i);
}
for(int i=mid+1;i<=r;i++)
{
c[++m]=event(3*(a[i].x-a[i].r)-1,3,i);
c[++m]=event(3*(a[i].x+a[i].r)-1,3,i);
}
sort(c+1,c+m+1,cmp2);
for(int i=1;i<=m;i++)
if(c[i].op==1)
s.insert(pii(a[c[i].v].y,c[i].v));
else if(c[i].op==2)
s.erase(pii(a[c[i].v].y,c[i].v));
else
{
auto it=s.lower_bound(pii(a[c[i].v].y,0));
if(it!=s.end())
{
int x=it->second;
if(inter(x,c[i].v))
ans[c[i].v]=min(ans[c[i].v],x);
}
if(it!=s.begin())
{
it--;
int x=it->second;
if(inter(x,c[i].v))
ans[c[i].v]=min(ans[c[i].v],x);
}
}
m=0;
for(int i=l;i<=mid;i++)
if(b[i])
{
c[++m]=event(3*(a[i].y-a[i].r)-2,1,i);
c[++m]=event(3*(a[i].y+a[i].r),2,i);
}
for(int i=mid+1;i<=r;i++)
{
c[++m]=event(3*(a[i].y-a[i].r)-1,3,i);
c[++m]=event(3*(a[i].y+a[i].r)-1,3,i);
}
sort(c+1,c+m+1,cmp2);
for(int i=1;i<=m;i++)
if(c[i].op==1)
s.insert(pii(a[c[i].v].x,c[i].v));
else if(c[i].op==2)
s.erase(pii(a[c[i].v].x,c[i].v));
else
{
auto it=s.lower_bound(pii(a[c[i].v].x,0));
if(it!=s.end())
{
int x=it->second;
if(inter(x,c[i].v))
ans[c[i].v]=min(ans[c[i].v],x);
}
if(it!=s.begin())
{
it--;
int x=it->second;
if(inter(x,c[i].v))
ans[c[i].v]=min(ans[c[i].v],x);
}
}
solve(mid+1,r);
}
int main()
{
open("circle");
scanf("%d",&n);
ll minx=0x7fffffff,miny=0x7fffffff;
for(int i=1;i<=n;i++)
{
// scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].r);
a[i].x=rd();
a[i].y=rd();
a[i].r=rd();
a[i].id=i;
minx=min(minx,a[i].x);
miny=min(miny,a[i].y);
}
for(int i=1;i<=n;i++)
{
a[i].x=a[i].x-minx+1;
a[i].y=a[i].y-miny+1;
}
sort(a+1,a+n+1,cmp);
memset(ans,0x7f,sizeof ans);
solve(1,n);
for(int i=1;i<=n;i++)
final[a[i].id]=a[ans[i]].id;
for(int i=1;i<=n;i++)
printf("%d ",final[i]);
printf("\n");
return 0;
}
【LOJ2586】【APIO2018】选圆圈 CDQ分治 扫描线 平衡树的更多相关文章
- LOJ2586 APIO2018 选圆圈
考前挣扎 KD树好题! 暴力模拟 通过kd树的结构把子树内的圈圈框起来 然后排个序根据圆心距 <= R1+R2来判断是否有交点 然后随便转个角度就可以保持优越的nlgn啦 卡精度差评 必须写ep ...
- 「APIO2018选圆圈」
「APIO2018选圆圈」 题目描述 在平面上,有 \(n\) 个圆,记为 \(c_1, c_2, \ldots, c_n\) .我们尝试对这些圆运行这个算法: 找到这些圆中半径最大的.如果有多个半径 ...
- BZOJ 1492 货币兑换 cdq分治或平衡树维护凸包
题意:链接 方法:cdq分治或平衡树维护凸包 解析: 这道题我拒绝写平衡树的题解,我仅仅想说splay不要写挂,insert边界条件不要忘.del点的时候不要脑抽d错.有想写平衡树的去看140142或 ...
- 【BZOJ4285】使者 cdq分治+扫描线+树状数组
[BZOJ4285]使者 Description 公元 8192 年,人类进入星际大航海时代.在不懈的努力之下,人类占领了宇宙中的 n 个行星,并在这些行星之间修建了 n - 1 条星际航道,使得任意 ...
- 【BZOJ1492】【Luogu P4027】 [NOI2007]货币兑换 CDQ分治,平衡树,动态凸包
斜率在转移顺序下不满足单调性的斜率优化\(DP\),用动态凸包来维护.送命题. 简化版题意:每次在凸包上插入一个点,以及求一条斜率为\(K\)的直线与当前凸包的交点.思路简单实现困难. \(P.s\) ...
- BZOJ5465 APIO2018选圆圈(KD-Tree+堆)
考虑乱搞,用矩形框圆放KD-Tree上,如果当前删除的圆和矩形有交就递归下去删.为防止被卡,将坐标系旋转一定角度即可.注意eps稍微设大一点,最好开上long double. #include< ...
- [BZOJ5465][APIO2018]选圆圈(KD-Tree)
题意:给你n个圆,每次选择半径最大的,将它和与它相交的圆全部删去,输出每个圆是在哪次被删的. KD树模板题.用一个矩形框住这个圆,就可以直接剪枝了.为了防止被卡可以将点旋转一个角度,为了保险还可以多转 ...
- [BZOJ1492][NOI2007]货币兑换Cash(斜率优化+CDQ分治)
1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 5838 Solved: 2345[Submit][Sta ...
- 【APIO2018】选圆圈(平面分块 | CDQ分治 | KDT)
Description 给定平面上的 \(n\) 个圆,用三个参数 \((x, y, R)\) 表示圆心坐标和半径. 每次选取最大的一个尚未被删除的圆删除,并同时删除所有与其相切或相交的圆. 最后输出 ...
随机推荐
- 逛csdn看见的一个知识阶梯,感觉不错
逛csdn看见的一个知识阶梯,感觉不错: 计算机组成原理 → DOS命令 → 汇编语言 → C语言(不包括C++).代码书写规范 → 数据结构.编译原理.操作系统 → 计算机网络.数据库原理.正则表 ...
- zabbix server3.4 使用mailx配置邮件报警
软件具体配置如下: 操作系统:Centos7.5 zabbix server版本:zabbix server3.4 zabbix agent版本:zabbix agent3.0 现在开始配置zabbi ...
- PSP总结报告
此作业的要求参见[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2556] 回顾0 alpha阶段前 团队名称:可以低头,但没必要 团队项 ...
- (四)版本控制管理器之VSS
在上一篇<(二)版本控制管理器值CVS(下)>的文章中,我为大家介绍了CVS这个版本控制器,接下来我继续跟大家分享介绍下一个版本控制管理器--VSS,为什么要说这个版本控制器呢?早已过时的 ...
- Windows应急响应常识
Windows 应急响应 常见事件ID 1102 清理审计日志 4624 账号登陆成功 4625 账号登陆失败 4672 授予特殊权限 4720 创建用户 4726 删除用户 4728 将成员添加到启 ...
- 如何在MongoDB设计存储你的数据(JSON化)?
第一步 定义要描述的数据集 当我们决定将数据存储下来的时候,我们首先要回答的一个问题就是:“我打算存储什么样的数据?这些数据之间有什么关系?实体之间有什么关系?实体的属性之间有什么关系”. 为了说明问 ...
- 【公众号系列】SAP HANA和区块链
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[公众号系列]SAP HANA和区块链 写在 ...
- 【原】Java学习笔记023 - 字符串缓冲区_正则表达式
package cn.temptation; import java.util.Arrays; public class Sample01 { public static void main(Stri ...
- Linux常见系统故障
Linux常见系统故障 1.修复MBR扇区故障 2.修复GRUB引导故障 3./etc/inittab文件丢失 4.遗忘root用户密码 5.修复文件系统 6.磁盘资源耗尽故障 一.修复MBR扇区故障 ...
- git 忽略 .idea文件
多人开发时,会出现明明在gitignore中忽略了.idea文件夹,但是提交时仍旧会出现.idea内文件变动的情况 原因.idea已经被git跟踪,之后再加入.gitignore后是没有作用的 解决办 ...