[BZOJ4561][JLoi2016]圆的异或并(扫描线+splay)
来源:互联网 发布:如寡人者 安与知耻 编辑:程序博客网 时间:2024/06/07 14:06
题目描述
传送门
题目大意:在平面直角坐标系中给定N个圆。已知这些圆两两没有交点,即两圆的关系只存在相离和包含。求这些圆的异或面积并。异或面积并为:当一片区域在奇数个圆内则计算其面积,当一片区域在偶数个圆内则不考虑。
题解
这题并没有做出来。。想了很多很多种不科学的方法。。
首先对于一个圆来说,可以将其分成上半个圆弧和下半个圆弧,并且在扫描整个圆的过程中(对于每一个横坐标),两个圆弧的相对位置不变。对于圆之间的相对包含关系,可以搞成一棵树(森林),奇数层的面积加偶数层的面积减就行了。
将每一个圆搞出左边界和右边界,然后按照x坐标排序做扫描线。遇到一个圆的左边界,在splay中插入两个点,分别表示这个圆的上半弧和下半弧。插入的时候需要利用圆的解析式计算一下之前splay中的点在当前横坐标x时的纵坐标y来判断插入位置。
插入之后找一下刚插入的上半弧的前驱。如果前驱是某一个圆的上半弧说明这个圆就是最小的包含当前圆的圆,如果是下半弧说明当前圆和这个圆的被包含关系相同,如果没有前驱则说明这个圆没有被任何圆包含。
遇到圆的右端点把两个圆弧都从splay里删除掉。
这样就做完了
代码
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 400005int n,cnt,root,sz;long long ans;struct C{int x,y,r;}c[N];struct OPT{int x,id,val;}opt[N];int f[N],ch[N][2],type[N],id_in_graph[N],id_in_splay[N][2],h[N];int cmp(OPT a,OPT b){return a.x<b.x||(a.x==b.x&&a.val<b.val);}int get(int x){ return ch[f[x]][1]==x;}void rotate(int x){ int old=f[x],oldf=f[old],wh=get(x); ch[old][wh]=ch[x][wh^1]; if (ch[old][wh]) f[ch[old][wh]]=old; ch[x][wh^1]=old; f[old]=x; if (oldf) ch[oldf][ch[oldf][1]==old]=x; f[x]=oldf;}void splay(int x){ for (int fa;(fa=f[x]);rotate(x)) if (f[fa]) rotate((get(x)==get(fa))?fa:x); root=x;}int compare(int ty,int id,double x,double y){ double a=c[id].x,b=c[id].y,r=c[id].r; double z; if (!ty) z=sqrt(r*r-(x-a)*(x-a))+b; else z=-sqrt(r*r-(x-a)*(x-a))+b; return z>=y;}void insert(int id){ if (!root) { root=++sz; type[sz]=0; id_in_splay[id][0]=sz; id_in_graph[sz]=id; f[++sz]=sz-1;ch[sz-1][1]=sz;type[sz]=1; id_in_splay[id][1]=sz; id_in_graph[sz]=id; return; } int now=root,fa=0,val=c[id].y; while (1) { int wh=compare(type[now],id_in_graph[now],c[id].x-c[id].r,c[id].y); fa=now; now=ch[now][wh]; if (!now) { ch[fa][wh]=++sz;f[sz]=fa;type[sz]=0; id_in_splay[id][0]=sz; id_in_graph[sz]=id; ch[sz][1]=sz+1;f[sz+1]=sz;type[++sz]=1; id_in_splay[id][1]=sz; id_in_graph[sz]=id; splay(sz-1); return; } }}void del(int x){ splay(x);int oldroot=root,leftbig; if (!ch[root][0]&&!ch[root][1]) { root=0; return; } if (!ch[root][0]) { root=ch[oldroot][1]; f[root]=0; return; } if (!ch[root][1]) { root=ch[oldroot][0]; f[root]=0; return; } leftbig=ch[root][0]; while (ch[leftbig][1]) leftbig=ch[leftbig][1]; splay(leftbig); ch[root][1]=ch[oldroot][1]; f[ch[root][1]]=root; return;}int findpre(){ int x=ch[root][0]; if (!x) return -1; while (ch[x][1]) x=ch[x][1]; return x;}int main(){ scanf("%d",&n); for (int i=1;i<=n;++i) { scanf("%d%d%d",&c[i].x,&c[i].y,&c[i].r); opt[++cnt].x=c[i].x-c[i].r,opt[cnt].id=i,opt[cnt].val=1; opt[++cnt].x=c[i].x+c[i].r,opt[cnt].id=i,opt[cnt].val=-1; } sort(opt+1,opt+cnt+1,cmp); for (int i=1;i<=cnt;++i) { int id=opt[i].id; if (opt[i].val==-1) { del(id_in_splay[id][0]); del(id_in_splay[id][1]); } else { insert(opt[i].id); int pre=findpre(); if (pre==-1) h[id]=1; else { if (type[pre]==0) h[id]=h[id_in_graph[pre]]+1; else h[id]=h[id_in_graph[pre]]; } if (h[id]&1) ans+=(long long)c[id].r*c[id].r; else ans-=(long long)c[id].r*c[id].r; } } printf("%lld\n",ans);}
感谢ATP的数据生成器
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<ctime>#define random(x)(rand()*rand()%x+1)using namespace std;int n,X[10010],Y[10010],R[10010];int getrand(int lim){ return random(lim)-random(lim);}double Abs(double x){return (x<0)?-x:x;}bool check(int x,int y,int r,int id){ double dx=x-X[id],dy=y-Y[id]; dx=sqrt(dx*dx+dy*dy); if (Abs(r-R[id])<=dx&&Abs(r+R[id])>=dx) return true; return false;}int main(){ freopen("input.in","w",stdout); n=100;srand(time(0)); printf("%d\n",n); for (int i=1;i<=n;){ int x,y,r; bool flag=false; x=getrand(100);y=getrand(100);r=random(100); for (int j=1;j<i;j++) if (check(x,y,r,j)){ flag=true;break; } if (flag==true) continue; X[i]=x;Y[i]=y;R[i]=r;i++; } for (int i=1;i<=n;i++) printf("%d %d %d\n",X[i],Y[i],R[i]); return 0;}
0 0
- [BZOJ4561][JLoi2016]圆的异或并(扫描线+splay)
- 【bzoj4561】【JLOI2016】【圆的异或并】【扫描线+set】
- BZOJ4561 [JLoi2016]圆的异或并
- BZOJ4561: [JLoi2016]圆的异或并
- bzoj4561【JLOI2016】圆的异或并
- bzoj 4561: [JLoi2016]圆的异或并 (计算几何+扫描线+splay)
- bzoj 4561: [JLoi2016]圆的异或并(扫描线+set)
- [扫描线 set] BZOJ 4561 [JLoi2016]圆的异或并
- [JLOI2016] 圆的异或并
- 4561: [JLoi2016]圆的异或并
- 4561 [JLoi2016] 圆的异或并
- 【LNOI/JLOI/SHOI2016】【BZOJ4561】圆的异或并
- BZOJ 4561 [JLoi2016]圆的异或并
- jzoj4996&&bzoj4561 关于扫描线
- 【BZOJ2758】Blinker的噩梦,扫描线+splay+链剖
- [BZOJ2584][Wc2012]memory(扫描线+splay+线段树)
- 圆的扫描线
- HDU 4007 Dave (线段树扫描线 或 暴力+双扫描线)
- 51Nod-1310-Chandrima and XOR
- 【转自eguid大神】实时监控、直播流、流媒体、视频网站开发方案设计简要
- [bigdata-61] centos 6.8 安装mysql 5.1.73
- Bellman-Ford的队列优化
- Druid
- [BZOJ4561][JLoi2016]圆的异或并(扫描线+splay)
- ContentProvider和Cursor以及CursorAdapter三者之间内部链接实现原理 解析
- 第9节 Linux内核学习总结【Linux内核分析】
- pytorch学习笔记
- 孤儿进程和僵尸进程
- MySQL CRASH COURSE命令总结(第六章过滤数据)
- PHP 文件下载功能
- 操作系统调度算法
- 工具篇1------sed