【NOIP模拟赛】天神下凡 动态开点线段树

这些圆一定是在同一水平面上的,由于他们没有相交,因此我们发现他们每个人与外界关系可以分为,1.存在并圈圈 2.存在圈圈并被割,因此我们把所有的圆都加1,把被割的在加1,就可以啦,因此我们开一个线段树,维护一段区间有没有被全部覆盖

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#define R register
#define MAXN 300000
using namespace std;
typedef unsigned long UI;
struct O
{
    UI x,r;
}o[MAXN+10];
int n;
int comp(const O a,const O b)
{
    return a.r<b.r;
}
struct Seg_Tree
{
    bool cover;
    UI l,r,mid;
    Seg_Tree *ch[2];
 
}*root;
inline Seg_Tree *New(UI l,UI r)
{
    R Seg_Tree *p=new Seg_Tree;
    p->cover=0;
    p->l=l;
    p->r=r;
    p->mid=((long long)l+r)>>1;
    p->ch[1]=p->ch[0]=NULL;
    return p;
}
bool query(Seg_Tree *p,UI l,UI r)
{
    if(p->cover)return 1;
    if(l<=p->l&&p->r<=r)return p->cover;
    R bool ans=1;
    if(l<=p->mid)
    {
       if(!p->ch[0])return 0;
       else ans&=query(p->ch[0],l,r);
    }
    if(p->mid<r)
    {
       if(!p->ch[1])return 0;
       else ans&=query(p->ch[1],l,r);
    }
    return ans;
}
void ins(Seg_Tree *p,UI l,UI r)
{
    if(p->cover)return;
    if(l<=p->l&&p->r<=r)
    {
        p->cover=1;
        return;
    }
    if(l<=p->mid)
    {
       if(!p->ch[0]) p->ch[0]=New(p->l,p->mid);
       ins(p->ch[0],l,r);
    }
    if(p->mid<r)
    {
       if(!p->ch[1]) p->ch[1]=New(p->mid+1,p->r);
       ins(p->ch[1],l,r);
    }
    if(p->ch[0]&&p->ch[1])p->cover=p->ch[0]->cover&p->ch[1]->cover;
}
inline void Init()
{
    scanf("%d",&n);
    for(R int i=1;i<=n;i++)
    {
        R int x,r;
        scanf("%d%d",&x,&r);
        o[i].x=(long long)x+2000000005;
        o[i].r=r;
    }
    sort(o+1,o+n+1,comp);
    root=New(1,4000000010LL);
}
inline void work()
{
    R int ans=1;
    for(int i=1;i<=n;i++)
    {
        ++ans;
        if(query(root,o[i].x-o[i].r,o[i].x+o[i].r))++ans;
        ins(root,o[i].x-o[i].r,o[i].x+o[i].r);
    }
    printf("%d",ans);
}
int main()
{
    Init();
    work();
    return 0;
}
原文地址:https://www.cnblogs.com/TSHugh/p/7260373.html