题目链接:https://vijos.org/p/1883
这道题还有另外一种版本叫天神下凡,属于模拟题,可是模拟题数据太水以至于模拟题A了都不一定在vijos上A。。。。
在模拟题里我用的是一种类似扫描线的方式,完美AC,然后在vijos上就是只能过2组
最后经同学提点改为递归才A了
这道题我们把圆看成线段,所以这题就是线段覆盖,然后答案是被完全覆盖的线段数+所有线段数+1
被完全覆盖的线段的数量就用递归找,不断的找被当前线段完全包含的线段,然后判断是否在里面
然后这道题有一种特殊情况可以不用执行程序,就是所有圆都是同心圆的时候,因为这种状态只存在重合和包含(本题重合不算完全覆盖),直接输出圆的数量+1即可
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio>
2 #include<cstring>
3 #include<iostream>
4 #include<cmath>
5 #include<algorithm>
6 #define maxn 300005
7 #define ll long long
8 using namespace std;
9
10 ll n,cnt,can,ans;
11 struct node{
12 ll l,r;
13 }e[maxn];
14
15 ll read(){
16 ll xx=0;ll ff=1;char ch=getchar();
17 while(ch<'0'||ch>'9'){if(ch=='-')ff=-1;ch=getchar();}
18 while(ch>='0'&&ch<='9'){xx=xx*10+ch-'0';ch=getchar();}
19 return xx*ff;
20 }
21
22 int cmp(node a,node b){
23 if(a.l==b.l ){
24 return a.r>b.r;
25 }return a.l<b.l;
26 }
27
28 int t;
29 int check (ll id){
30 int now=e[id].l,add=1,ret=0;
31 while(t!=n+1&&e[t].r<=e[id].r){
32 if(e[t].l!=now)add=0;
33 now=e[t].r;
34 ret+=check(t++);
35 }
36 if(now!=e[id].r )add=0;
37 return 1+ret+add;
38 }
39
40 int main(){
41 n=read();
42 for(ll i=1;i<=n;i++){
43 ll x,R;
44 x=read();R=read();
45 e[i].l=x-R;e[i].r=x+R;
46 if(cnt==0)cnt=x;
47 if(cnt!=x)can=1;
48 }
49 if(!can){cout<<n+1;return 0; }//同一个圆心可以不管了
50 sort(e+1,e+n+1,cmp);t=1;
51 while(t!=n+1){
52 ans+=check(t++);
53 } ans=ans+1;
54 cout<<ans;
55 }
然后这道题还有一个解法就是线段树,因为不存在相交的情况,所以不需要使用lazy标记,没有lazy标记的线段树就很简单了
但是要注意一点就是这些左右端点在坐标轴上,坐标轴有可能很大,所以要用到离散化