1. 程式人生 > >poj 2528(線段樹+離散化)

poj 2528(線段樹+離散化)

如圖,貼海報,後面的海報可以貼在前面的海報的上面,按給定的順序在區間為(l,r)的位置去貼海報,問最後可以在表面看見的海報有多少張


給定的區間範圍很大,為1 <= li <= ri <= 10000000

靜態的話,直接用線段樹進行區間更新,需要1000000個葉子節點,還沒TLE就已經MLE了

但是海報的數目1 <= n <= 10000,所以進行離散化

例如

1 4,2 6,9,12三張海報

1,2,4,6,9,12  普通線段樹需要12個葉節點

離散化思想

seg[0]=1,seg[1]=2,seg[2]=4,seg[3],seg[4]=6,seg[5]=9,seg[6]=12

此時 線段區間由1—12壓縮到了0—6,

本題特殊的地方在於,如果區間序列為[1,10],[1,4],[9,10]

那麼

i             0      1      2      3

seg        1      4      9       10


如圖,[0,0]和[1,1]記錄了第二張海報,[2,2]和[3,3]記錄了第三章海報

計算答案為2,但實際答案為3,第一張海報還是可以看見的

解決方法在4後面插入5,變成

i             0      1      2      3        4

seg        1      4       5      9       10

!!這題陣列開的奇大無比,試了好多次一直RE
segTree[maxn*16+5];


程式碼如下,
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

const int maxn=11111;

struct node1
{
    int l,r,id;
}segTree[maxn*16+5];
struct node2
{
    int l,r;
}poster[maxn+5];
bool vis[10010];
int seg[4*maxn+5];
int ans;
void push_down(int i)
{
    if(segTree[i].id!=-1){
        segTree[i<<1].id=segTree[i].id;
        segTree[(i<<1)|1].id=segTree[i].id;
        segTree[i].id=-1;
    }
}

void build(int i,int l,int r)
{
    segTree[i].l=l;
    segTree[i].r=r;
    segTree[i].id=-1;
    if(l==r)return;
    int mid=(l+r)/2;
    build(i<<1,l,mid);
    build((i<<1)|1,mid+1,r);
}

void update(int i,int l,int r,int id)
{
    if(segTree[i].l==l&&segTree[i].r==r){
        segTree[i].id=id;
        return;
    }
    push_down(i);
    int mid=(segTree[i].l+segTree[i].r)/2;
    if(r<=mid)update(i<<1,l,r,id);
    else if(mid<l)update((i<<1)|1,l,r,id);
    else{
        update(i<<1,l,mid,id);
        update((i<<1)|1,mid+1,r,id);
    }
}

void query(int i,int l,int r)
{
    if(segTree[i].id!=-1){//不用判斷區間,之間檢查染色情況
        if(!vis[segTree[i].id]){
            vis[segTree[i].id]=true;
            ans++;
        }
        segTree[i].id=-1;
        return;
    }
    if(l==r)return;
    push_down(i);
    int mid=(segTree[i].l+segTree[i].r)/2;
    if(r<=mid)query(i<<1,l,r);
    else if(l>mid)return query((i<<1)|1,l,r);
    else {
        query(i<<1,l,mid);
        query((i<<1)|1,mid+1,r);
    }
}

int BSearch(int low,int high,int num)
{
    int mid;
    while(low<=high){
        mid=(low+high)/2;
        if(num==seg[mid])return mid;
        else if(seg[mid]>num)high=mid-1;
        else low=mid+1;
    }
    return low;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int c,n,cnt,m;
    scanf("%d",&c);
    while(c--){
        memset(vis,0,sizeof(vis));
        cnt=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%d%d",&poster[i].l,&poster[i].r);
            seg[cnt++]=poster[i].l;seg[cnt++]=poster[i].r;
        }
        sort(seg,seg+cnt);
        m=1;
        for(int i=1;i<cnt;i++)
            if(seg[i]!=seg[i-1])seg[m++]=seg[i];
        for(int i=m-1;i>=1;i--)
            if(seg[i]-seg[i-1]>1)seg[m++]=seg[i-1]+1;
        sort(seg,seg+m);
        build(1,1,m);
        for(int i=0;i<n;i++){
            int l=BSearch(0,m-1,poster[i].l);//利用二分查詢離散處理後的位置
            int r=BSearch(0,m-1,poster[i].r);
            update(1,l+1,r+1,i);
        }
        ans=0;
        query(1,1,m);
        printf("%d\n",ans);
    }
    return 0;
}