[洛谷2434] [SDOI2005]区间 线段树

题目描述

现给定n个闭区间[ai, bi],1<=i<=n。这些区间的并可以表示为一些不相交的闭区间的并。你的任务就是在这些表示方式中找出包含最少区间的方案。你的输出应该按照区间的升序排列。这里如果说两个区间[a, b]和[c, d]是按照升序排列的,那么我们有a<=b<c<=d。

请写一个程序:

读入这些区间;

计算满足给定条件的不相交闭区间;

把这些区间按照升序输出。

输入输出格式

输入格式:

第一行包含一个整数n,3<=n<=50000,为区间的数目。以下n行为对区间的描述,第i行为对第i个区间的描述,为两个整数1<=ai<bi<=1000000,表示一个区间[ai, bi]。

输出格式:

输出计算出来的不相交的区间。每一行都是对一个区间的描述,包括两个用空格分开的整数,为区间的上下界。你应该把区间按照升序排序。


题解:

其实这题有很多简单的方法可以解决,但我们为了练习线段树的能力,用线段树来实现它。我们把区间[u,v]变成[u*2,v*2],并每次对这个区间整体+1,这样可以保证两个区间的边界处不会被增加。然后枚举出现过的数,一个个统计答案即可。

AC代码:

#include<cstdio>
#include<iostream>
#define ll int
using namespace std;
const int Maxn=2000015;
ll a[Maxn];
struct node{
    ll x,c;
    int l,r; 
}t[Maxn*8]; 
int m;
inline int lson(int x){
    return x*2;
}
inline int rson(int x){
    return x*2+1;
}
inline int pushup(int rt){
    t[rt].x=t[lson(rt)].x+t[rson(rt)].x;
}
inline void build(int l,int r,int rt){
    t[rt].l=l;t[rt].r=r;
    if(l==r){
        t[rt].x=a[l];
        return;
    }
    int mid=l+r>>1;
    build(l,mid,lson(rt));
    build(mid+1,r,rson(rt));
    pushup(rt);
}
inline int len(int rt){
    return t[rt].r-t[rt].l+1;
}
inline void pushdown(int rt){
    if(t[rt].l==t[rt].r)return;
    if(t[rt].c==0)return;
    t[lson(rt)].c+=t[rt].c;
    t[rson(rt)].c+=t[rt].c;
    t[lson(rt)].x+=t[rt].c*len(lson(rt));
    t[rson(rt)].x+=t[rt].c*len(rson(rt));
    t[rt].c=0;
}
inline void update(int l,int r,ll x,int rt){
    if(t[rt].l>=l&&t[rt].r<=r){
        t[rt].x+=x*len(rt);
        t[rt].c+=x;
        return;
    }
    pushdown(rt);
    int mid=t[rt].l+t[rt].r>>1;
    if(l<=mid){
        update(l,r,x,lson(rt));
    }
    if(r>mid){
        update(l,r,x,rson(rt));
    }
    pushup(rt);
}
inline ll query(int l,int rt){
    if(t[rt].l==l&&t[rt].r==l){
        return t[rt].x;
    }
    pushdown(rt);
    int mid=t[rt].l+t[rt].r>>1;
    if(l<=mid)return query(l,lson(rt));
    else return query(l,rson(rt));
}
inline int mx(int x,int y){
    return x>y?x:y;
}
int main(){
    int u,v,inc,maxn,now=1;
    bool flag=1;
    scanf("%d",&m);
    build(1,2000005,1);
    while(m--){
        scanf("%d%d",&u,&v);
        update(u*2,v*2,1,1);
        maxn=mx(maxn,v*2);
    }
    while(now<=maxn){
        if(flag==0){
            printf("%d ",now/2);
            while(query(now,1)&&now<=maxn)now++;
            printf("%d\n",now/2);
            flag=1;
        }
        else{
            while(!query(now,1)&&now<=maxn)now++;
            flag=0;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lvyanchang/article/details/80712341