4561: [JLoi2016]圆的异或并
Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 715 Solved: 277
[ Submit][ Status][ Discuss]
Description
在平面直角坐标系中给定N个圆。已知这些圆两两没有交点,即两圆的关系只存在相离和包含。求这些圆的异或面积并。异或面积并为:当一片区域在奇数个圆内则计算其面积,当一片区域在偶数个圆内则不考虑。
Input
第一行包含一个正整数N,代表圆的个数。接下来N行,每行3个非负整数x,y,r,表示一个圆心在(x,y),半径为r的圆。保证|x|,|y|,≤10^8,r>0,N<=200000
Output
仅一行一个整数,表示所有圆的异或面积并除以圆周率Pi的结果。
Sample Input
2
0 0 1
0 0 2
Sample Output
3
很显然如果该圆在偶数个圆里面,那么它的面积对答案贡献就是正的
如果该圆在奇数个圆里面,那么它的面积对答案贡献就是负的
将每个圆拆成两个点(x-r和x+r)
之后从左到右扫描,扫到一个圆就看它上面最近的一个圆是正贡献还是负贡献,具体看下图
其中当遍历到图中第二小的那个圆的左端时
很显然它上面最靠近它的圆面积是正的,
但是你首先遇到的会是B点,而B点在大圆的下方,所以可知当前小圆面积也是正的
计算完之后将该圆插入
……
同理遍历到图中最小的圆时,
虽然它最上面的最靠近它的圆面积也是正的,但竖线交点那个点在大圆的上方,所以面积为负
……
当遍历到图中第二小的那个圆的右端时,说明整个圆已经没有意义了,删除该圆,其它同理
可以用set维护,用set查询上面最靠近的圆
#include<stdio.h>
#include<set>
#include<math.h>
#include<algorithm>
using namespace std;
#define LL long long
typedef struct Res
{
int x, y, r;
int t, val, id;
}Circle;
Circle s[600005], c[300005], temp;
typedef struct Pset
{
int id, t, val;
bool operator < (const Pset &b) const
{
if(id==0)
return 1;
else if(b.id==0)
return 0;
else if(id==b.id)
{
if(t>b.t)
return 1;
return 0;
}
else
{
if(c[id].y+t*sqrt((LL)c[id].r*c[id].r-(LL)(temp.x-c[id].x)*(temp.x-c[id].x))>c[b.id].y+b.t*sqrt((LL)c[b.id].r*c[b.id].r-(LL)(temp.x-c[b.id].x)*(temp.x-c[b.id].x)))
return 1;
return 0;
}
}
}Pset;
Pset now;
set<Pset> st;
bool comp(Circle a, Circle b)
{
if(a.x<b.x || a.x==b.x && a.t<b.t || a.x==b.x && a.t==b.t && a.t*a.r>b.t*b.r)
return 1;
return 0;
}
int main(void)
{
LL ans = 0;
set<Pset>::iterator it;
int cnt, n, i;
scanf("%d", &n);
cnt = 0;
for(i=1;i<=n;i++)
{
scanf("%d%d%d", &c[i].x, &c[i].y, &c[i].r);
s[++cnt].x = c[i].x-c[i].r, s[cnt].y = c[i].y, s[cnt].t = 1, s[cnt].r = c[i].r, s[cnt].id = i;
s[++cnt].x = c[i].x+c[i].r, s[cnt].y = c[i].y, s[cnt].t = -1, s[cnt].r = c[i].r, s[cnt].id = i;
}
n = cnt;
sort(s+1, s+n+1, comp);
now.id = 0, now.val = -1, now.t = 1;
st.insert(now);
for(i=1;i<=n;i++)
{
if(s[i].t==1)
{
temp = s[i];
now.id = s[i].id;
now.t = 1;
it = --st.upper_bound(now);
if((*it).t==1)
now.val = -(*it).val;
else
now.val = (*it).val;
s[i].val = now.val;
ans += (LL)now.val*temp.r*temp.r;
st.insert(now);
now.t = -1;
st.insert(now);
}
else
{
now.id = s[i].id;
now.t = 1;
st.erase(now);
now.t = -1;
st.erase(now);
}
}
printf("%lld\n", ans);
return 0;
}
/*
3
0 0 4
0 2 2
0 -2 2
*/