UPC 5725 小奇画画

题目描述

红莲清泪两行欲吐半点却无
如初是你杳然若绯雾还在水榭畔画楼处
是谁衣白衫如初谁红裳如故
——《忆红莲》

小奇想画几朵红莲,可惜它刚开始学画画,只能从画圆开始。小奇画了n个圆,它们的圆心都在x轴上,且两两不相交(可以相切)。现在小奇想知道,它画的圆把画纸分割成了多少块?(假设画纸无限大)

输入

第一行包括1个整数n。
接下来n行,每行两个整数x,r,表示小奇画了圆心在(x,0),半径为r的一个圆。

输出

输出一个整数表示答案。

样例输入

4 
7 5 
-9 11 11 9 
0 20

样例输出

6

提示

对于 100%数据,1<=n<=300000,-10^9<=x<=10^9,1<=r<=10^9。

 

思路:UPC上的数据很水,做题的时候用左右端点排序再map标记水过去后果然一次重判被HACK。赛后找了些重判后还是A的代码研究了下,找了几组数据竟然还能hack掉。。。。。

1.学弟有个思路是在优先队列中左端点升序排列,右端点升序排列,然后左端点相同的两条线段可以处理成由二者右端点分别作为左右端点的新线段,将线段用map标记,判断此新线段是否已经出现过,否则放入队列,感觉很巧妙。

2.队友思路是离散化后用线段树区间查询修改,利用tree[rt].biao=min(tree[rt<<1].biao,tree[rt<<1|1].biao)来判断区间是否全覆盖.感觉挺稳的一个做法,但是鉴于这题背后水水的数据,额。。应该没毛病。

补充:修改时用R-1是因为我们处理的是区间覆盖问题 我们把一个点代表成一个小线段 2-3 4-5 这两个小线段实际覆盖只有2后面和4后面一段小区间 所以3是没有被标记的,如果后面来了一个2-5的线段,不rr-1的话3也会被标记,这样答案就不对了。所以这里需要通过rr-1来实现这一步。

 

交UPCoj的时候要删掉注释,,,,不删超时,删了890ms有毒。。

 

代码:

#include
using namespace std;
#define ll long long
const int maxn=3e5+10;

struct nod{
    int x,r;
    int l,rr;
}no[maxn];


struct tri{
    int l,r;
    int b;
    int mark;
}tr[maxn*8];
int pos[maxn*2];

map ma;

bool cmp(nod a,nod b){
    if(a.r==b.r) return a.l     else return a.r }

void push_up(int rt){
    tr[rt].b=min(tr[rt<<1].b,tr[rt<<1|1].b);
}

void build(int rt,int l,int r ){
    tr[rt].l=l;
    tr[rt].r=r;
    tr[rt].mark=0;
//    printf("%d--%d  %d\n",rt,tr[rt].l,tr[rt].r);

    if(l==r){
        tr[rt].b=0;
        return ;
    }
    ll mid=(l+r)/2;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    push_up(rt);
}

void push_down(int rt){
    if(tr[rt].mark){
        tr[rt<<1].mark+=tr[rt].mark;
        tr[rt<<1|1].mark+=tr[rt].mark;
        tr[rt<<1].b+=tr[rt].mark;
        tr[rt<<1|1].b+=tr[rt].mark;
        tr[rt].mark=0;
    }
}

void upd(int rt,int l,int r,int val){
//    printf("---%d----",rt);
    if(l<=tr[rt].l&&r>=tr[rt].r){
        tr[rt].mark+=val;
        tr[rt].b+=val;
        return ;
    }
    push_down(rt);
    int mid=(tr[rt].l+tr[rt].r)/2;
    if(l<=mid) upd(rt<<1,l,r,val);
    if(r>mid)  upd(rt<<1|1,l,r,val);
    push_up(rt);
}


int que(int rt,int l,int r){
//    printf("--%d--",rt);
    int ans=0x3f3f3f3f;
    if(l<=tr[rt].l && r>=tr[rt].r){
        return tr[rt].b;
    }
    push_down(rt);
    int mid=(tr[rt].l+tr[rt].r)/2;
    if(l<=mid) ans=min(ans,que(rt<<1,l,r));
    if(r>mid) ans=min(que(rt<<1|1,l,r),ans);
    return ans;
}

 

int main(){
    int n;
    while(~scanf("%d",&n)){
        ma.clear();
        memset(pos,0,sizeof(pos));
        for(int i=1;i<=n;i++) scanf("%d%d",&no[i].x,&no[i].r);
        int cnt=0;
        for(int i=1;i<=n;i++){
            int tem=no[i].x;
            no[i].l=tem-no[i].r;
            no[i].rr=tem+no[i].r;
            pos[++cnt]=no[i].l;
            pos[++cnt]=no[i].rr;
        }

        sort(pos+1,pos+1+cnt);
        int k=2;
        ma[pos[1]]=1;

        for(int i=2;i<=cnt;i++){
            if(pos[i]==pos[i-1]) continue;
            else ma[pos[i]]=k++;
        }

        for(int i=1;i<=n;i++) no[i].l=ma[no[i].l],no[i].rr=ma[no[i].rr];

        sort(no+1,no+1+n,cmp);

//        for(int i=1;i<=n;i++) printf("%d  %d\n",no[i].l,no[i].rr);
        build(1,1,k-1);
        ll ans=n+1;
        for(int i=1;i<=n;i++){
//            printf("##%d\n",i);
            int x=que(1,no[i].l,no[i].rr-1);
//            printf("\n");
            if(x){
//                printf("----%d   %d  %d\n",i,no[i].l,no[i].rr);
                ans++;
            }
            upd(1,no[i].l,no[i].rr-1,1);
//            printf("\n");
        }

        printf("%lld\n",ans);
    }
}


/*

4

0 8

4 4

-4 4

-2 2

*/

///队友牛逼!

你可能感兴趣的:(离散化,xianduanshu)