题目描述
传送门
题目大意:在平面直角坐标系中给定N个圆。已知这些圆两两没有交点,即两圆的关系只存在相离和包含。求这些圆的异或面积并。异或面积并为:当一片区域在奇数个圆内则计算其面积,当一片区域在偶数个圆内则不考虑。
题解
首先两个圆的相对位置是不会改变的。
上图中的三个圆与三条直线相交会形成上下两个交点,如果把交点看成是左右括号,那么括号序列的相对关系是不变的(如果存在同一条直线上),靠上的两个圆如果同时与其中一条直线相交那么必然是包含的关系。
我们将每个圆看成是一对括号,那么对于扫描到的位置其实就是一段合法的括号序列,我们用splay来维护他,splay 按照与直线交点的纵坐标有序。一个圆插入他的上端点(左括号),如果他的前驱也是左括号,那么他被覆盖的次数就是前一个的答案+1,如果是右括号,那么与前一个是并列的关系,所有与前一个的答案相同。
对于一个圆我们在扫描到x-r的时候加入,x+r的时候删除。
那么最终的答案就是被覆盖奇数次的圆的面积-被覆盖偶数次的圆的面积。
代码
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#define N 500003
#define inf 1000000000
#define LL long long
using namespace std;
int l[N],r[N],val[N],opt[N],num[N],ch[N][3],fa[N],n,root,sz,cnt;
double T;
struct data{
double x;
int id,val;
data(double X=0,int I=0,int V=0) {
x=X,id=I,val=V;
}
}q[N];
struct cir{
double x,y,r;
}c[N];
int cmp(data a,data b)
{
return a.x<b.x;
}
int get(int x)
{
return ch[fa[x]][1]==x;
}
void rotate(int x)
{
int y=fa[x]; int z=fa[y]; int which=get(x);
ch[y][which]=ch[x][which^1]; fa[ch[x][which^1]]=y;
if (z)
ch[z][ch[z][1]==y]=x;
fa[x]=z; ch[x][which^1]=y; fa[y]=x;
}
void splay(int x,int tar)
{
for (int f;(f=fa[x])!=tar;rotate(x))
if (fa[f]!=tar)
rotate(get(x)==get(f)?f:x);
if (!tar) root=x;
}
int pre()
{
int now=ch[root][0];
while (ch[now][1]) now=ch[now][1];
return now;
}
int next()
{
int now=ch[root][1];
while (ch[now][0]) now=ch[now][0];
return now;
}
double pow(double x)
{
return x*x;
}
void insert(int now,int h,double v)
{
if(!root) {
++sz; root=sz; val[sz]=0;
opt[sz]=1; num[sz]=0;
return;
}
int x=root;
while (true)
{
int t=val[x]; double vk=0;
if (!t) vk=(opt[x]==1)?-inf:inf;
else {
double xx=c[t].y-sqrt(pow(c[t].r)-pow(c[t].x-T));
double yy=c[t].y+sqrt(pow(c[t].r)-pow(c[t].x-T));
vk=(opt[x]==1)?xx:yy;
}
int f=x;
x=ch[x][v>=vk];
if (!x) {
++sz; fa[sz]=f; ch[f][v>=vk]=sz;
val[sz]=now; opt[sz]=h;
if (h==1) {
splay(sz,0); l[now]=sz;
int pr=pre();
num[sz]=(opt[pr]==1)?num[pr]+1:num[l[val[pr]]];
}else r[now]=sz;
break;
}
}
}
void del(int x)
{
splay(x,0);
int a=pre(); int b=next();
splay(a,0); splay(b,a);
ch[ch[root][1]][0]=0;
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++) {
scanf("%lf%lf%lf",&c[i].x,&c[i].y,&c[i].r);
q[++cnt]=data(c[i].x-c[i].r,i,1);
q[++cnt]=data(c[i].x+c[i].r,i,-1);
}
sort(q+1,q+cnt+1,cmp);
insert(0,1,-inf); insert(0,2,inf);
LL ans=0;
for (int i=1;i<=cnt;i++) {
T=q[i].x; int now=q[i].id;
if (q[i].val==1) insert(now,1,c[now].y),insert(now,2,c[now].y);
if (q[i].val==-1){
del(l[now]),del(r[now]);
if (num[l[now]]&1) ans+=pow(c[now].r);
else ans-=pow(c[now].r);
}
}
printf("%lld\n",ans);
}