小奇画画
小奇画画
题目描述
小奇想画几朵红莲,可惜它刚开始学画画,只能从画圆开始。小奇画了n个圆,它们的圆心都在x轴上,且两两不相交(可以相切)。
现在小奇想知道,它画的圆把画纸分割成了多少块?(假设画纸无限大)
输入格式
第一行包括1个整数n。
接下来n行,每行两个整数x,r,表示小奇画了圆心在(x,0),半径为r的一个圆。
输出格式
输出一个整数表示答案。
样例
样例输入
4
7 5
-9 11
11 9
0 20
样例输出
6
数据范围与提示
对于30%数据,n<=5000;
对于100%数据,1<=n<=300000,-10^9<=x<=10^9,1<=r<=10^9。
思路:我们先思考若最普通最简单的情况(本来也没多少情况)即每个圆相外切,块数为n+1,画图就能发现不管是相内切还是大圆套小圆只要一个大圆中的小圆没连在一起把这个大圆分成两半,块数都为n+1,所以这个题就是找出好多小圆把大圆分成两半的情况。
首先想到的暴力:将圆按照左边界排序(右边界大的放在前面便于判断大圆是否被分成两部分),大圆被分成两部分+2,否则+1。
还可以用并查集,先离散化,再将每个圆的左右边界连上(放在一个并查集中),若已经联通+2,否则+1
并查集代码
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int maxn=300000+10; 5 int fa[maxn<<1]; 6 struct Node{ 7 int l,r; 8 }a[maxn]; 9 int Find_root(int x){ 10 return fa[x]==x?x:(fa[x]=Find_root(fa[x])); 11 } 12 int point[maxn<<1]; 13 int main(){ 14 int n; 15 scanf("%d",&n); 16 int tot=0; 17 for(int i=1;i<=n;i++){ 18 int x,R; 19 scanf("%d%d",&x,&R); 20 a[i].l=x-R; 21 a[i].r=x+R; 22 point[++tot]=a[i].l; 23 point[++tot]=a[i].r;//记录左右端点,便于离散化 24 } 25 sort(point+1,point+1+tot); 26 int m=unique(point+1,point+1+tot)-point-1;//去重 27 for(int i=1;i<=n;i++){ 28 a[i].l=lower_bound(point+1,point+m,a[i].l)-point; 29 a[i].r=lower_bound(point+1,point+m,a[i].r)-point;//离散化 30 } 31 int cnt=0; 32 for(int i=1;i<=tot;i++) fa[i]=i; 33 for(int i=1;i<=n;i++){ 34 int fl=Find_root(a[i].l); 35 int fr=Find_root(a[i].r); 36 if(fl!=fr){ 37 cnt++;//不联通+1 38 fa[fl]=fr; 39 } 40 else cnt+=2;//联通+2 41 } 42 cnt++;//注意最后一大块画板也计数 43 printf("%d\n",cnt); 44 return 0; 45 }