当某个圆被多个连续相切的小圆分成上下两部分时块数+2,其他情况块数+1。
上面的情况时最外面的圆被分成上下两部分所以+2,其他小圆每个+1,初始为1;
所以只需要判断有多少个+2的,最后再+圆的个数+1;
建图把每个大圆里直接包含的小圆建一条边,然后判断每个大圆直接相连的所有小圆的r的和是否等于大圆的r就可以
建图的话先按照左端点小到大排序,左端点相等的话按右端点大到小排序,然后用stack建图。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
vector<int> v[300005];
struct node
{
ll left,right,x,r;
}a[300005];
int cmp(node a,node b)
{
if(a.left==b.left)
return a.right>b.right;
return a.left<b.left;
}
int sum[300005]={0};
int dfs()
{
int ans=0;
queue<int>q;//先进先出
for(int i=0;i<n;i++)
{
if(!sum[i])
q.push(i);
}
while(!q.empty())
{
int t=q.front();
q.pop();
ll temp=0;
for(int i=0;i<v[t].size();i++)
{
int u=v[t][i];
temp+=a[u].r;
q.push(u);
}
if(temp==a[t].r)
ans++;
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%lld%lld",&a[i].x,&a[i].r);
a[i].left=a[i].x-a[i].r;
a[i].right=a[i].x+a[i].r;
}
sort(a,a+n,cmp);
stack<ll> s; //后进先出
for(int i=0;i<n;i++)
{
while(!s.empty())
{
int t=s.top();
if(a[i].right<=a[t].right)
{
v[t].push_back(i);
sum[i]++;
break;
}
s.pop();
}
s.push(i);
}
int ans=dfs();
printf("%d\n",ans+n+1);
return 0;
}