P6875 [COCI2013-2014#6] KRUŽNICE
由样例可以知道,一个圆只贡献一个区域,而一个圆在中间被几个圆完全连接时会被分成两个部分,计算两个贡献。
那么我们很容易想到先按照左端点排序,在左端点相同时,比较半径大小。
然后从后向前连接,如果前面与当前点的左端相等,那么我们就可以通过这个圆尝试把前面的圆分成两部分。
然后记录下状态,如果前面刚好有一个圆的右端点,则直接连接,继承到当前位置。
如果发现此时的右端点与尝试分开的圆的右端点相等,那么就记录贡献。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,f[300005],ans;
map<int,int> mp;
struct P{
int x,r;
}a[300005];
bool cmp(P a,P b){
if(a.x-a.r==b.x-b.r)return a.r>b.r;
return a.x-a.r<b.x-b.r;
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].r;
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++){
if(mp[a[i].x-a[i].r])f[i]=mp[a[i].x-a[i].r];
if(i!=1){
if(a[i].x-a[i].r==a[i-1].x-a[i-1].r)f[i]=i-1;
}
if(f[i]&&a[i].x+a[i].r==a[f[i]].x+a[f[i]].r)ans++,f[i]=0;
if(f[i])mp[a[i].x+a[i].r]=f[i];
}
cout<<ans+n+1;
return 0;
}

浙公网安备 33010602011771号