[洛谷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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章