洛谷 P3268 [JLOI2016]圆的异或并

题目描述

在平面上有两两不相交的\(n\)个圆,即其关系只有相离和包含。求这些圆的异或面积并。

异或面积并为:当一片区域被奇数个圆包含则计算其面积,否则不计算。

输出所有圆的异或面积并除以\(\pi\)的结果。

\(n\le 200000\)。

Solution

前置知识:扫描线,set。

可以发现,由于圆是不相交的,那么这种包含关系可以看作是一棵森林(许多有根树构成的图)。

比如像这个几个圆

可以变成

设每个根的深度为1,那么深度为奇数的节点的面积是需要加上的,深度为偶数的节点的面积是需要减去的。

\[ans=\sum_{i=1}^nr_i^2\times(-1)^{dep_i+1}
\]

同扫描线的思想,我们模拟出有一条垂直于\(x\)轴的直线从左向右移动。

  • 当其与某个圆开始触碰到的时候,就将这个圆拆分为上半圆和下半圆插入set中。这个set是按照圆的高度排序的。由于保证了圆和圆之间不相交,所以可以直接计算扫描线与半圆的交点作为关键字排序。圆和圆之间不相交保证了这个关键字的相对大小一定不会变。

查询刚刚插入的圆的上半圆的前驱(在set中的所有半圆中,在当前圆下方最近的半圆)。如果它的前驱是一个上半圆,那么当前圆的深度等于其前驱的深度;若前驱是一个下半圆,那么说明当前圆被其前驱所包含,深度为前驱的深度+1。

  • 遇到圆的右边界就直接将其两个半圆从set中删除即可。

因为set中要插入同一id的两个半圆,那么只要用up表示当前圆是上半圆还是下半圆即可。重载运算符时,可以比较当前扫描线与半圆的交点,也可以以圆心的纵坐标为第一关键字,以上/下半圆为第二关键字进行比较。

注意,如果是以扫描线与半圆的交点进行比较的话,在扫描线进入/离开一个圆的时候,扫描线与两个半圆的交点会重合。需要在比较函数中将上半圆的交点纵坐标加上一个\(eps\)即可。

Code

我的排序方法是比较当前半圆和扫描线的交点

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<limits.h>
#define IL inline
#define re register
#define LL long long
#define ULL unsigned long long
#ifdef TH
#define debug printf("Now is %d\n",__LINE__);
#else
#define debug
#endif
using namespace std; template<class T>inline void read(T&x)
{
char ch=getchar();
int fu;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') fu=-1,ch=getchar();
x=ch-'0';ch=getchar();
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
x*=fu;
}
inline LL read()
{
LL x=0,fu=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') fu=-1,ch=getchar();
x=ch-'0';ch=getchar();
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*fu;
}
int G[55];
template<class T>inline void write(T x)
{
int g=0;
if(x<0) x=-x,putchar('-');
do{G[++g]=x%10;x/=10;}while(x);
for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar('\n');
}
#define N 200010
int n,nowx;
LL X[N],Y[N],R[N];
struct Opt
{
LL pos;
int x;
bool insert;
Opt(LL a=0,int b=0,bool c=0)
{
pos=a,x=b,insert=c;
}
IL bool operator<(const Opt& z)const
{
return pos<z.pos;
}
};
vector<Opt>opt;
bool dep[N];
#define eps 1e-6
struct O
{
int x;
bool up;
O(int xx=0,bool u=1)
{
x=xx,up=u;
}
double calc()const
{
if(up) return Y[x]+sqrt(R[x]*R[x]-(X[x]-nowx)*(X[x]-nowx))+eps;
return Y[x]-sqrt(R[x]*R[x]-(X[x]-nowx)*(X[x]-nowx));
}
IL bool operator<(const O& z)const
{
return calc()<z.calc();
}
};
set<O>s;
set<O>::iterator it;
int main()
{
n=read();
for(int i=1;i<=n;i++)
{
X[i]=read();
Y[i]=read();
R[i]=read();
opt.push_back(Opt(X[i]-R[i],i,1));
opt.push_back(Opt(X[i]+R[i],i,0));
}
sort(opt.begin(),opt.end());
LL ans=0;
for(int i=0;i<opt.size();i++)
{
nowx=opt[i].pos;
if(opt[i].insert)
{
it=s.insert(O(opt[i].x,1)).first;
if(it==s.begin())
{
dep[opt[i].x]=1;
}
else
{
it--;
if(it->up)
{
dep[opt[i].x]=dep[it->x];
}
else
{
dep[opt[i].x]=dep[it->x]^1;
}
}
s.insert(O(opt[i].x,0));
if(dep[opt[i].x]) ans+=R[opt[i].x]*R[opt[i].x];
else ans-=R[opt[i].x]*R[opt[i].x];
}
else
{
s.erase(O(opt[i].x,1));
s.erase(O(opt[i].x,0));
}
}
write(ans);
return 0;
}

总结

扫描线是一种重要的思想。在其应用的过程中常常需要用到set​,线段树等数据结构进行维护。

洛谷 P3268 [JLOI2016]圆的异或并的更多相关文章

  1. 洛谷P3268 [JLOI2016]圆的异或并(扫描线)

    扫描线还不是很熟啊--不管是从想的方面还是代码实现的方面-- 关于这题,考虑一条平行于\(y\)轴的扫描线从左到右扫描每一个圆,因为只有相离和内含两种关系,只用在切线处扫描即可 我们设上半圆为1,下半 ...

  2. bzoj4561: [JLoi2016]圆的异或并 圆的扫描线

    地址:http://www.lydsy.com/JudgeOnline/problem.php?id=4561 题目: 4561: [JLoi2016]圆的异或并 Time Limit: 30 Sec ...

  3. BZOJ4561 JLoi2016 圆的异或并 【扫描线】【set】*

    BZOJ4561 JLoi2016 圆的异或并 Description 在平面直角坐标系中给定N个圆.已知这些圆两两没有交点,即两圆的关系只存在相离和包含.求这些圆的异或面积并.异或面积并为:当一片区 ...

  4. 【BZOJ4561】[JLoi2016]圆的异或并 扫描线

    [BZOJ4561][JLoi2016]圆的异或并 Description 在平面直角坐标系中给定N个圆.已知这些圆两两没有交点,即两圆的关系只存在相离和包含.求这些圆的异或面积并.异或面积并为:当一 ...

  5. 洛谷 P4592: bzoj 5338: [TJOI2018]异或

    题目传送门:洛谷P4592. 题意简述: 题面说的很清楚了. 题解: 发现没有修改很快乐.再看异或最大值操作,很容易想到可持久化 01trie. 这里要把 01trie 搬到树上,有点难受. 树剖太捞 ...

  6. bzoj4561: [JLoi2016]圆的异或并

    Description 在平面直角坐标系中给定N个圆.已知这些圆两两没有交点,即两圆的关系只存在相离和包含.求这些圆的异或面 积并.异或面积并为:当一片区域在奇数个圆内则计算其面积,当一片区域在偶数个 ...

  7. bzoj 4561: [JLoi2016]圆的异或并

    Description 在平面直角坐标系中给定N个圆.已知这些圆两两没有交点,即两圆的关系只存在相离和包含.求这些圆的异或面 积并.异或面积并为:当一片区域在奇数个圆内则计算其面积,当一片区域在偶数个 ...

  8. BZOJ 4561 [JLoi2016]圆的异或并 ——扫描线

    扫描线的应用. 扫描线就是用数据结构维护一个相对的顺序不变,带修改的东西. 通常只用于一次询问的情况. 抽象的看做一条垂直于x轴直线从左向右扫过去. 这道题目要求求出所有圆的异或并. 所以我们可以求出 ...

  9. [JLOI2016]圆的异或并

    Description 在平面直角坐标系中给定N个圆.已知这些圆两两没有交点,即两圆的关系只存在相离和包含.求这些圆的异或面积并.异或面积并为:当一片区域在奇数个圆内则计算其面积,当一片区域在偶数个圆 ...

  10. 洛谷 P3267 - [JLOI2016/SHOI2016]侦察守卫(树形 dp)

    洛谷题面传送门 经典题一道,下次就称这种"覆盖距离不超过 xxx 的树形 dp"为<侦察守卫模型> 我们考虑树形 \(dp\),设 \(f_{x,j}\) 表示钦定了 ...

随机推荐

  1. ocr识别过程中报错 tesseract is not installed

    这个问题无论在初始编译时或者在后来坏境变更调试时都会遇到的问题. 解决:问题原因是源码中的默认路径位置与文件位置不同,需要更改一下

  2. C语言中标准输出的缓冲机制

    什么是缓冲区 缓存区是内存空间的一部分,再内存中,内存空间会预留一定的存储空间,这些存储空间是用来缓冲输入和输出的数据,预留的这部分空间就叫做缓冲区. 其中缓冲区还会根据对应的是输入设备还是输出设备分 ...

  3. 关闭windows计划重启

    前言 windows 总是自动计划更新 解决方案 需要禁用服务 "Windows Update" 和 "更新 Orchestrator 服务" 首先去这里下载P ...

  4. IM服务器:一个使用imserver服务器进行聊天的web端案例

    该案例中包含一个基于web网页的前端程序,该案例会使用websocket与IM服务器(imserver)进行通信. 一.环境准备 1.下载 "imserver网页调用案例",并解压 ...

  5. nginx服务和uwsgi服务如何设置开机自启动

    上次学到了在云服务器下如何部署Django项目,用到了nginx服务和uwsgi服务,需要手工启动这2个服务的命令. 现在考虑如何设置开机自启动,为什么要这样考虑?因为服务器万一出问题,意外重启了,那 ...

  6. linux怎么关闭selinux

    关闭方法:1.临时关闭,只需执行"setenforce 0"命令即可.2.永久关闭,需要执行"vi /etc/selinux/config"命令打开config ...

  7. RANSAC---从直线拟合到特征匹配去噪

    Ransac全称为Random Sample Consensus,随机一致性采样.该方法是一种十分高效的数据拟合方法.我们通过最简单的拟合直线任务来了解这种方法思路,继而扩展到特征点匹配中的误点剔除问 ...

  8. 【C#】Winform嵌入dll到exe中

    [C#]Winform嵌入dll到exe中 零.问题 最近在做一个上位机,需要保存数据,所以引用了一些Excel的组件,但是比较麻烦的是会多出几个DLL文件,压缩打包不方便使用,于是想能不能嵌入到ex ...

  9. Win10微软拼音输入法设置-注册表

    修改候选项窗口 HKEY_CURRENT_USER\Software\Microsoft\InputMethod\CandidateWindow\CHS\1 EnableFixedCandidateC ...

  10. Python 潮流周刊#96:MCP 到底是什么?(摘要)

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...