问题 D: 天神下凡
时间限制: 3 Sec 内存限制: 256 MB提交: 52 解决: 36
题目描述
Czy找到宝藏获得屠龙宝刀和神秘秘籍!现在他要去找经常ntr他的Jmars报仇……
Czy学会了一招“堕天一击”,他对一个地点发动堕天一击,地面上就会留下一个很大的圆坑。圆坑的周围一圈能量太过庞大,因此无法通过。所以每次czy发动技能都会把地面分割。Jmars拥有好大好大的土地,几十眼都望不到头,所以可以假设土地的大小是无限大。现在czy对他发动了猛烈的攻击,他想知道在泽宇攻击之后他的土地被切成几份了?
Czy毕竟很虚,因此圆心都在x坐标轴上。另外,保证所有圆两两之间不会相交。
输入
输入第一行为整数n,表示czy放了n次堕天一击。
接下来n行,每行两个整数x[i],r[i]。表示在坐标(x[i] , 0)放了一次堕天一击,半径为r[i]。
输出
输出一行,表示地面被分割成几块。
样例输入
47 5-9 1111 90 20
样例输出
6
复习一下数学高考知识(虽然众所周知的我数学偏科) 圆与圆之间的五种位置关系:相交、内切、外切、相离、内含 第一种题目里排除了,剩下的所有情况正常情况下都是多一个圆都多一个区域。 还多考虑了一下重复的圆,不过不知道有没有这种数据 加上剩下的无限大土地,就是以 不重复的圆的数目+1 为基准 至于多出来的,都是因为有圆被多个圆内切,整个把圆切成了两半 先把圆排序 (我是按左边界从小到大、左边界相同的右边界从大到小排的序,这样排主要是为了保证能内切 本圆的圆都在它后面) 枚举各个圆,肯定要O(n)的效率,只能尽量优化一下判断部分 刚开始想用类似单调队列的办法,发现也不是那么容易维护,就在每个点建了个堆,堆顶是目前 这个圆内部最靠右的圆的右边界 这个合理性好像是可以证?因为不相交所以它就合理了,如果有圆相切它一定左边界连着堆顶 priority_queue< int, vector<int> ,less<int> > a; for(int i=1;i<=n;i++) { while(!a.empty()) a.pop(); for(int j=i+1;j<=n;j++) { if(c[j].zj>=c[i].yj) break; if(a.empty()||a.top()==c[j].zj) a.push(c[j].yj); if(!a.empty()&&a.top()==c[i].yj) { jg++; break; } } } 因为判断的复杂度比较玄学,最后的复杂度也不好说,比如说第一个点那个同心圆卡得比其他点慢 了好几倍 听说大佬们用的线段树,怎么做的?
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
#include<cstdlib>
#include<algorithm>
#define V 300005
#define mod 1000000007
#define LL long long
using
namespace
std;
int
n;
map<LL,
int
>ma;
int
sd[V*2];
priority_queue<
int
, vector<
int
> ,less<
int
> > a;
int
id;
struct
da
{
int
l,r;
}st[V];
inline
int
cmp(da x,da y)
{
if
(x.l==y.l)
return
x.r>y.r;
return
x.l<y.l;
}
inline
int
haha()
{
//freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
//freopen("treas.in","r",stdin); freopen("treas.out","w",stdout);
int
x,y;
cin>>n;
for
(
int
i=1;i<=n;i++)
{
//cin>>x>>y;
scanf
(
"%d%d"
,&x,&y);
st[i].l=x-y;
st[i].r=x+y;
sd[0]++;
sd[sd[0]]=x-y;
sd[0]++;
sd[sd[0]]=x+y;
}
sort(st+1,st+n+1,cmp);
//cout<<st[1].l<<" "<<st[2].l;
sort(sd+1,sd+sd[0]+1);
for
(
int
i=1;i<=sd[0];i++)
{
if
(!ma[sd[i]])
{
ma[sd[i]]=++id;
}
}
for
(
int
i=1;i<=n;i++)
{
st[i].l=ma[st[i].l];
st[i].r=ma[st[i].r];
}
int
jd=0;
for
(
int
i=1;i<=n;i++)
{
while
(!a.empty())a.pop();
for
(
int
j=i+1;j<=n;j++)
{
if
(st[j].l>=st[i].r)
{
break
;
}
if
(a.empty()||a.top()==st[j].l)
a.push(st[j].r);
if
(!a.empty()&&a.top()==st[i].r)
{
jd++;
break
;
}
}
//cout<<st[i].l<<" "<<st[i].r<<endl;
}
cout<<jd+n+1;
//<<" "<<jd<<" "<<n;
return
0;
}
int
gg=haha();
int
main()
{;}