【LNOI/JLOI/SHOI2016】【BZOJ4561】圆的异或并
2016-07-02 16:44
323 查看
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4561
还是头一次回头写自己参加过的比赛的题
记得当时没开long long还以为要爆零。。。虽然最后还是滚粗了
言归正传
这题的算法叫扫描法,就是说把所有可能导致圆的上下关系变化的关键x值找到,然后从小到大进行扫描,找到圆的关系
这里的关键x是每个圆的水平直径的两个端点横坐标,也就是一个圆被扫到的起始和结束点
扫到圆C起始点时将C的上半圆和下半圆分别加入平衡树(set也好啊)然后找下半圆的前驱。若前驱为另一个圆O的下半圆,则C包含在O中,C计算面积时的方法与O相反(O加则C减);若前驱为O的上半圆,则C与O同级,C计算方法与O相同。特殊地,若C的下半圆没有前驱,则计算C时要加上它的面积,因为C不被任何圆包含。
//被坑了两次之后,我算是发现double比较大小有多不准了,解决方法详见代码40行
#include<cstdio>
#include<set>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 200005
#define long long long
int n;
double X;
struct circle
{
long x;
long y;
long r;
int parametre;
void read(){scanf("%lld%lld%lld",&x,&y,&r);}
long area(){return r*r*parametre;}
double dis(){return sqrt(r*r-(x-X)*(x-X));}
}full[maxn];
struct keypoint
{
circle *belong;
long x;
int end;
keypoint(circle *c,int t):belong(c),end(t){x=c->x+c->r*t;}
keypoint(){};
}kp[maxn*2];
struct arch
{
circle *belong;
int type;
arch(circle *c,int t):belong(c),type(t){}
double y()
{
return (double)belong->y+belong->dis()*type;
}
};
bool operator < (arch a,arch b)
{
return ((a.y()==b.y())?a.type<b.type:a.y()<b.y());
}
bool operator < (const keypoint &a,
const keypoint &b){return a.x<b.x;}
set<arch> arc;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
full[i].read();
kp[i*2-1]=keypoint(full+i,-1);
kp[i*2]=keypoint(full+i,1);
}
sort(kp+1,kp+1+2*n);
for(int i=1;i<=2*n;i++)
{
X=kp[i].x;
if(kp[i].end==1) arc.erase(arch(kp[i].belong,-1)),arc.erase(arch(kp[i].belong,1));
else
{
arc.insert(arch(kp[i].belong,-1));
arc.insert(arch(kp[i].belong,1));
set<arch>::iterator it=arc.find(arch(kp[i].belong,-1));
if(it==arc.begin()) kp[i].belong->parametre=1;
else
{
it--;
kp[i].belong->parametre=it->type*(it->belong->parametre);
}
}
}
long ans=0;
//for(int i=1;i<=n;i++) printf("%d %d\n",i,full[i].parametre);
for(int i=1;i<=n;i++) ans+=full[i].area();
printf("%lld\n",ans);
return 0;
}
还是头一次回头写自己参加过的比赛的题
记得当时没开long long还以为要爆零。。。虽然最后还是滚粗了
言归正传
这题的算法叫扫描法,就是说把所有可能导致圆的上下关系变化的关键x值找到,然后从小到大进行扫描,找到圆的关系
这里的关键x是每个圆的水平直径的两个端点横坐标,也就是一个圆被扫到的起始和结束点
扫到圆C起始点时将C的上半圆和下半圆分别加入平衡树(set也好啊)然后找下半圆的前驱。若前驱为另一个圆O的下半圆,则C包含在O中,C计算面积时的方法与O相反(O加则C减);若前驱为O的上半圆,则C与O同级,C计算方法与O相同。特殊地,若C的下半圆没有前驱,则计算C时要加上它的面积,因为C不被任何圆包含。
//被坑了两次之后,我算是发现double比较大小有多不准了,解决方法详见代码40行
#include<cstdio>
#include<set>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 200005
#define long long long
int n;
double X;
struct circle
{
long x;
long y;
long r;
int parametre;
void read(){scanf("%lld%lld%lld",&x,&y,&r);}
long area(){return r*r*parametre;}
double dis(){return sqrt(r*r-(x-X)*(x-X));}
}full[maxn];
struct keypoint
{
circle *belong;
long x;
int end;
keypoint(circle *c,int t):belong(c),end(t){x=c->x+c->r*t;}
keypoint(){};
}kp[maxn*2];
struct arch
{
circle *belong;
int type;
arch(circle *c,int t):belong(c),type(t){}
double y()
{
return (double)belong->y+belong->dis()*type;
}
};
bool operator < (arch a,arch b)
{
return ((a.y()==b.y())?a.type<b.type:a.y()<b.y());
}
bool operator < (const keypoint &a,
const keypoint &b){return a.x<b.x;}
set<arch> arc;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
full[i].read();
kp[i*2-1]=keypoint(full+i,-1);
kp[i*2]=keypoint(full+i,1);
}
sort(kp+1,kp+1+2*n);
for(int i=1;i<=2*n;i++)
{
X=kp[i].x;
if(kp[i].end==1) arc.erase(arch(kp[i].belong,-1)),arc.erase(arch(kp[i].belong,1));
else
{
arc.insert(arch(kp[i].belong,-1));
arc.insert(arch(kp[i].belong,1));
set<arch>::iterator it=arc.find(arch(kp[i].belong,-1));
if(it==arc.begin()) kp[i].belong->parametre=1;
else
{
it--;
kp[i].belong->parametre=it->type*(it->belong->parametre);
}
}
}
long ans=0;
//for(int i=1;i<=n;i++) printf("%d %d\n",i,full[i].parametre);
for(int i=1;i<=n;i++) ans+=full[i].area();
printf("%lld\n",ans);
return 0;
}
相关文章推荐
- 【Jason's_ACM_解题报告】Amphiphilic Carbon Molecules
- Garbage Heap
- Distant Galaxy
- City Game
- poj 3109 扫描线+bit
- UVa 1709 Amalgamated Artichokes
- UVALive 3029 City Game(最大子矩阵+悬线法)
- 连续子数组最大和问题编程实现
- [poj 1901] Hypertransmission:扫描法,适度暴力
- 单片机==独立按键+数码管计数+扫描法(8)
- LA 4356 Fire-Control System (扫描法)
- LA 4851 Restaurant (扫描法)
- 算法总结:【线段树+扫描线】&矩形覆盖求面积/周长问题(HDU 1542/HDU 1828)
- ACM 扫描法 Wine trading in Gergovia
- ZooKeeper学习之运维工具zkweb
- Spring并发访问的线程安全性问题
- OpenGL Frame BufferObject(FBO)
- codeforces_678D. Iterated Linear Function(快速幂)
- 用Python将多标签数据存入caffe使用的HDF5&LMDB格式
- 如何利用记事本编写并运行一个java程序