问题 G: 天神下凡

时间限制: 1 Sec  内存限制: 128 MB

题目描述

Czy找到宝藏获得屠龙宝刀和神秘秘籍!现在他要去找经常ntr他的Jmars报仇……
Czy学会了一招“堕天一击”,他对一个地点发动堕天一击,地面上就会留下一个很大的圆坑。圆坑的周围一圈能量太过庞大,因此无法通过。所以每次czy发动技能都会把地面分割。Jmars拥有好大好大的土地,几十眼都望不到头,所以可以假设土地的大小是无限大。现在czy对他发动了猛烈的攻击,他想知道在泽宇攻击之后他的土地被切成几份了?
Czy毕竟很虚,因此圆心都在x坐标轴上。另外,保证所有圆两两之间不会相交。

 

 

输入

输入第一行为整数n,表示czy放了n次堕天一击。
接下来n行,每行两个整数x[i],r[i]。表示在坐标(x[i] , 0)放了一次堕天一击,半径为r[i]。

 

 

输出

输出一行,表示地面被分割成几块。

 

样例输入

4
7 5
-9 11
11 9
0 20

样例输出

6

 

提示

对于30%数据,n<=5000
对于100%数据,1<=n<=300000,-10^9<=x[i]<=10^9,1<=r[i]<=10^9.

/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

int n, f[300005];

int sum[300005];

struct node
{
	int l, r, id;
	bool operator <(const node &x)const{
		return l == x.l ? r > x.r : l < x.l;
	}
}a[300005];

stack<node> st;

int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);

	scanf("%d", &n);
	int p, r;
	for (int i = 1; i <= n; i++){
		scanf("%d %d", &p, &r);
		a[i].l = p - r, a[i].r = p + r;
	}
	sort(a + 1, a + 1 + n);//将每个圆表示成线段,然后根据左小右大的顺序排序
	for (int i = 1; i <= n; i++){
		f[i] = i;
		a[i].id = i;
	}
	for (int i = 1; i <= n; i++){//求出各个圆被什么圆包围,是最小包围的圆,不是最外面的圆
		if(st.empty()){
			st.push(a[i]);
		}else{
			while(st.size()){
				node t = st.top();
				if(t.l <= a[i].l && a[i].r <= t.r){//如果别包围,标记
					f[i] = t.id;
					break;
				}else{
					st.pop();//否则找是否有包围它的圆,如果没有,出栈
					continue;
				}
			}
			st.push(a[i]);
		}
	}
	int ans = n + 1;
	for (int i = 1; i <= n; i++){
		if(f[i] != i){
			sum[f[i]] += a[i].r - a[i].l;
			if(sum[f[i]] == a[f[i]].r - a[f[i]].l) ans++;//因为没有相交的圆,所以如果多个圆的直径和恰好等于大圆,那么大圆的面就被分为2部分
		}
	}
	printf("%d\n", ans);

	return 0;
}
/**/