题目描述
背景
Czy C z y 找到宝藏获得屠龙宝刀和神秘秘籍!现在他要去找经常 ntr n t r 他的 Jmars J m a r s 报仇……
题目描述
Czy
C
z
y
学会了一招“堕天一击”,他对一个地点发动堕天一击,地面上就会留下一个
很大的圆坑。圆坑的周围一圈能量太过庞大,因此无法通过。所以每次
czy
c
z
y
发动技能都会把地面分割。
Jmars
J
m
a
r
s
拥有好大好大的土地,几十眼都望不到头,所以可以假设土地的大小是无限大。现在
czy
c
z
y
对他发动了猛烈的攻击,他想知道在泽宇攻击之后他的土地被切成几份了?
Czy
C
z
y
毕竟很虚,因此圆心都在 x 坐标轴上。另外,保证所有圆两两之间不会相交。
格式
输入第一行为整数
n
n
,表示 放了
n
n
次堕天一击。
接下来 n 行,每行两个整数 。表示在坐标
(x[i],0)
(
x
[
i
]
,
0
)
放了一次堕天一击,半
径为
r[i]
r
[
i
]
。
输出一行,表示地面被分割成几块。
数据范围
对于 30%数据,
n≤5000
n
≤
5000
对于 100%数据,
1≤n<=300000,−109≤x[i]≤109,1≤r[i]≤109
1
≤
n
<=
300000
,
−
10
9
≤
x
[
i
]
≤
10
9
,
1
≤
r
[
i
]
≤
10
9
.
题目解法
这道题实在没有什么高级解法,一个栈就可以解决。
具体想法就是由于所有的圆都在一条线上,所以,我们可以研究出:
- 一般来说一个圆就是一个贡献
- 如果一个圆被几个圆内切了,也就是说,从一个范围 [l,r] [ l , r ] 的圆说,如果有若干个 [l,p1],[p1,p2],....,[pn,r] [ l , p 1 ] , [ p 1 , p 2 ] , . . . . , [ p n , r ] 的圆,那么会产生额外的贡献。
- 我们的目标是找到额外的贡献与不重叠的圆的数量
基于此,我们可以模拟出一个过程。然而这一个过程需要从最左边的最大的圆开始,所以我们先排一个序。
排完序后,从最左边的一个圆开始入栈,那么入栈规则如下:
- 如果栈内是空的,直接入栈
- 栈内的元素始终保持为将来可能有贡献的,也就是将来可能被其它圆填满,为了达到这一点,我们需要:
- 把圆的圆心与半径转化为圆的范围 [l,r] [ l , r ] 。
- 放入一个元素时比较当前栈顶元素的范围,如果与栈顶的元素有着相同的左端点,那么栈顶元素继续可能被填满。不用删除,只需把栈顶元素的范围缩小,即栈顶元素的 l l 变成将加入的元素的,然后加入当前元素。
- 如果将加入的元素的范围 ⊊ ⊊ 栈顶元素的范围,那么栈顶元素弹出,继续比较下一层的元素。
- 如果该元素范围 ∩ ∩ 栈顶元素范围 =∅ = ∅ 那么栈顶元素弹出,继续比较下一层的元素。
- 如果该元素范围在栈顶元素的左边,那么加入当前元素。
分析了这么多,代码也很好理解了
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int _ =320031;
struct sta{
LL ld,rd;
}stk[_];
int n,top;
struct cir{
LL o,r;
}c[_];
bool operator == (cir a,cir b){
return (a.o==b.o)&(a.r==b.r);
}
bool cmp(cir a,cir b){
if(a.o-a.r!=b.o-b.r){
return a.o-a.r<b.o-b.r;
}
return a.o+a.r>b.o+b.r;
}
int main(){
freopen("god.in","r",stdin);
freopen("god.out","w",stdout);
ios::sync_with_stdio(false);
cin>>n;
for(register int i=1;i<=n;++i){
cin>>c[i].o>>c[i].r;
}
sort(c+1,c+n+1,cmp);
register int ans=1;
for(register int i=1;i<=n;++i){
if(c[i]==c[i-1])continue;
++ans;
register LL ld=c[i].o-c[i].r,rd=c[i].o+c[i].r;
while(top){
if(stk[top].ld==ld&&stk[top].rd==rd){
top--;
++ans;
break;
}
if(stk[top].ld==ld){
stk[top].ld=rd;
break;
}
if(ld>=stk[top].rd||(ld>stk[top].ld&&rd<stk[top].rd)){--top;}
else break;
}
stk[++top].ld=ld,stk[top].rd=rd;
}
cout<<ans;
}