bzoj 4561: [JLoi2016]圆的异或并(扫描线+set)

来源:互联网 发布:数控线切割编程软件 编辑:程序博客网 时间:2024/06/05 15:32

4561: [JLoi2016]圆的异或并

Time Limit: 30 Sec  Memory Limit: 256 MB
Submit: 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 longtypedef 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;elsenow.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;}/*30 0 40 2 20 -2 2*/


原创粉丝点击