洛谷 P3268 [JLOI2016]圆的异或并
洛谷 P3268 [JLOI2016]圆的异或并
题目描述
在平面上有两两不相交的\(n\)个圆,即其关系只有相离和包含。求这些圆的异或面积并。
异或面积并为:当一片区域被奇数个圆包含则计算其面积,否则不计算。
输出所有圆的异或面积并除以\(\pi\)的结果。
\(n\le 200000\)。
Solution
前置知识:扫描线,set。
可以发现,由于圆是不相交的,那么这种包含关系可以看作是一棵森林(许多有根树构成的图)。
比如像这个几个圆

可以变成

设每个根的深度为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]圆的异或并的更多相关文章
- 洛谷P3268 [JLOI2016]圆的异或并(扫描线)
扫描线还不是很熟啊--不管是从想的方面还是代码实现的方面-- 关于这题,考虑一条平行于\(y\)轴的扫描线从左到右扫描每一个圆,因为只有相离和内含两种关系,只用在切线处扫描即可 我们设上半圆为1,下半 ...
- bzoj4561: [JLoi2016]圆的异或并 圆的扫描线
地址:http://www.lydsy.com/JudgeOnline/problem.php?id=4561 题目: 4561: [JLoi2016]圆的异或并 Time Limit: 30 Sec ...
- BZOJ4561 JLoi2016 圆的异或并 【扫描线】【set】*
BZOJ4561 JLoi2016 圆的异或并 Description 在平面直角坐标系中给定N个圆.已知这些圆两两没有交点,即两圆的关系只存在相离和包含.求这些圆的异或面积并.异或面积并为:当一片区 ...
- 【BZOJ4561】[JLoi2016]圆的异或并 扫描线
[BZOJ4561][JLoi2016]圆的异或并 Description 在平面直角坐标系中给定N个圆.已知这些圆两两没有交点,即两圆的关系只存在相离和包含.求这些圆的异或面积并.异或面积并为:当一 ...
- 洛谷 P4592: bzoj 5338: [TJOI2018]异或
题目传送门:洛谷P4592. 题意简述: 题面说的很清楚了. 题解: 发现没有修改很快乐.再看异或最大值操作,很容易想到可持久化 01trie. 这里要把 01trie 搬到树上,有点难受. 树剖太捞 ...
- bzoj4561: [JLoi2016]圆的异或并
Description 在平面直角坐标系中给定N个圆.已知这些圆两两没有交点,即两圆的关系只存在相离和包含.求这些圆的异或面 积并.异或面积并为:当一片区域在奇数个圆内则计算其面积,当一片区域在偶数个 ...
- bzoj 4561: [JLoi2016]圆的异或并
Description 在平面直角坐标系中给定N个圆.已知这些圆两两没有交点,即两圆的关系只存在相离和包含.求这些圆的异或面 积并.异或面积并为:当一片区域在奇数个圆内则计算其面积,当一片区域在偶数个 ...
- BZOJ 4561 [JLoi2016]圆的异或并 ——扫描线
扫描线的应用. 扫描线就是用数据结构维护一个相对的顺序不变,带修改的东西. 通常只用于一次询问的情况. 抽象的看做一条垂直于x轴直线从左向右扫过去. 这道题目要求求出所有圆的异或并. 所以我们可以求出 ...
- [JLOI2016]圆的异或并
Description 在平面直角坐标系中给定N个圆.已知这些圆两两没有交点,即两圆的关系只存在相离和包含.求这些圆的异或面积并.异或面积并为:当一片区域在奇数个圆内则计算其面积,当一片区域在偶数个圆 ...
- 洛谷 P3267 - [JLOI2016/SHOI2016]侦察守卫(树形 dp)
洛谷题面传送门 经典题一道,下次就称这种"覆盖距离不超过 xxx 的树形 dp"为<侦察守卫模型> 我们考虑树形 \(dp\),设 \(f_{x,j}\) 表示钦定了 ...
随机推荐
- 【数值计算方法】线性方程组迭代算法的Python实现
线性方程组迭代算法的Python实现 jacobi,GS,SOR迭代法 def JacobiIter(A:np.ndarray, b:np.ndarray, tol:float=1e-5, maxIt ...
- 对接服务升级后仅支持tls1.2,jdk1.7默认使用tls1.0,导致调用失败
背景 如标题所说,我手里维护了一个重要的老项目,使用jdk1.7,里面对接了很多个第三方服务,协议多种多样,其中涉及http/https的,调用方式也是五花八门,比如:commons-httpclie ...
- pandas 删除指定条件的行
inplace=True:不创建新的对象,直接对原始对象进行修改: inplace=False:对数据进行修改,创建并返回新的对象承载其修改结果. 删除工作日餐补为0的记录 row_index=df[ ...
- linux(centos)配置ipv6网卡
1.ipv6网卡配置文件和ipv4在同一个网卡配置文件中 vim /etc/sysconfig/network-scripts/ifcfg-eth0 设置好之后重启网卡生效 2.测试
- linux 根目录与分区
1.2 根目录的建立 大家一般都会知道根目录的产生方式,就是系统使用mount指令,将系统所在的分区挂载到[/]目录中,这样便完成了所谓的根目录.但你是否想过, 虽然看起来合理却有点诡异,因为根目录 ...
- 入门Dify平台:工作流节点分析
要让智能体在实际应用中表现出色,掌握工作流的使用至关重要.今天,我们将深入探讨Dify平台中的各个节点的功能,了解它们的使用方法以及常见的应用场景.通过对这些节点的全面了解,将能够高效地设计和优化智能 ...
- 实现领域驱动设计 - 使用ABP框架 - 更新操作实体
用例演示 - 更新 / 操作实体 一旦一个实体被创建,它将被用例更新/操作,直到它从系统中删除.可以有不同类型的用例直接或间接地更改实体 在本节中,我们将讨论更改 Issue 的多个属性的典型更新操作 ...
- Sublime Text 3汉化教程
一.初始化插件仓库 ctrl+`(esc键下方那一个)打开控制台输入以下代码回车 import urllib.request,os,hashlib; h = '6f4c264a24d933ce70df ...
- STM32 DMA中的DMA_BufferSize和DMA_MemoryDataSize
示例代码1 采集2通道ADC数据 查看代码 extern uint16_t ADC3ConvertedValue[2]; /* DMA2 Stream0 channel2 配置 *********** ...
- 基于OpenCV与PyTorch的智能相册分类器全栈实现教程
引言:为什么需要智能相册分类器? 在数字影像爆炸的时代,每个人的相册都存储着数千张未整理的照片.手动分类不仅耗时,还容易遗漏重要瞬间.本文将手把手教你构建一个基于深度学习的智能相册分类系统,实现: 三 ...