POJ 2528 線段樹離散化

【題目鏈接】
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=14608

[解題報告】
題目大意:
給定長度區間(L,R)//L,R<=1e7,
給出N個區間操作,把li-ri區間貼上海報 //N《=1e5
求:有多少張海報沒有被完全覆蓋

這道題目的關鍵在於,直接開1e7的線段樹一定會MLE,但我們觀察到一共只有不超過1e5張海報,如果每張海報我們只取它的兩個端點,只對它的端點進行處理,空間複雜度就會大大降低。
所以如何處理呢?
比如區間[1,4],[5,6]有四個不同端點,說明我們需要把他映射到線段樹上四個不同的位置。
我們從1開始對線段樹的葉子節點進行標記,那麼映射到的相對應的線段樹區間爲:
[1,4]->[1,2]
[5,6]->[3,4]
這時候出現一個問題:
我們先後貼上[1,10],[1,4],[5,10],映射爲:[1,4],[1,2],[3,4]只能看見兩張海報
如果先後貼上[1,10],[1,4],[7,10],映射爲:[1,4],[1,2],[3,4],只能看見兩張海報。
哪裏出了問題?
問題在於:
如果兩條相鄰線段並不相交,離散化之後,它變成了相交!
所以維護這樣的性質:如果兩個頂點並不緊鄰,那麼我們離散化之後,它們仍然不能緊鄰。方法是在兩個頂點之間再插入一個頂點。

到了這裏,大部分問題就解決了。
還需要思考一個問題:如何查找沒有被完全覆蓋的海報的數目。
容易想到,我們更新的時候,給區間(l,r)打上標記i表示當前位置的海報是i,這樣最後統計有多少個不同的i即可。
爲了不重複查詢相同的,沒有被完全覆蓋的i,如: (1,10),( 3,4 ),(7,8)更新之後的標記就是1,2,1,3,1,會出現多個第1張海報的標記,我們需要單獨設置一個hash數組,如果某張海報已經被統計過了,就不再重複統計。

這樣,剩下的就是線段樹模板的內容了。
剩下的細節可以參考代碼。我的線段樹風格參考劉汝佳的《訓練指南》。

【參考代碼】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn=1e5+50;

int N,m,cnt;
int l[maxn],r[maxn],vis[maxn],X[maxn];
int cover[maxn*4];


void uniq( int nn )
{
    m=0;
    X[++m]=X[1];
    for( int i=2; i<=nn; i++ )
    {
        if( X[i]!=X[i-1] )X[++m]=X[i];
    }
    sort( X+1,X+1+m );
    int t=m;
    for( int i=1;i<t;i++ )
    {
        if( X[i]!=X[i+1]-1 )X[++m]=X[i]+1;
    }
    sort( X+1,X+1+m );
}

void build( int O, int L, int R )
{
    if(L==R)cover[O]=-1;
    else
    {
        int mid=(L+R)/2;
        build(O*2+1,mid+1,R );
        build( O*2,L,mid );
        cover[O]=-1;
    }
}

void pushdown( int O )
{
    if( cover[O]!=-1 )
    {
        cover[O*2]=cover[O*2+1]=cover[O];
        cover[O]=-1;
    }
}

void update( int O, int L, int R, int qL, int qR, int c )
{
    if( qL<=L && R<=qR )
    {
        cover[O]=c;
    }
    else
    {
        pushdown( O );
        int mid=(L+R)/2;
        if(  qL<=mid )update( O*2,L,mid, qL,qR,c );
        if( qR>mid )update( O*2+1, mid+1,R,qL,qR,c );
    }
}


void query( int O, int L, int R )
{
    if( L==R )
    {
        if( cover[O]!=-1 && !vis[cover[O]] )
        {
            vis[cover[O]]=1;
            cnt++;
        }
    }
    else
    {
        pushdown(O);
        int mid=(L+R)/2;
        query( O*2, L,mid );
        query( O*2+1,mid+1,R );
    }
}

int main()
{
    //freopen("2528","r",stdin);
    int T; cin>>T;
    while(T--)
    {
        scanf( "%d",&N );
        int nn=0;
        for(  int i=1; i<=N; i++ )
        {
             scanf( "%d%d",&l[i],&r[i] );
             X[++nn]=l[i]; X[++nn]=r[i];
        }
        sort( X+1,X+1+nn );
        uniq(nn);
        build( 1,1,m );
        for( int i=1; i<=N; i++ )
        {
            int left=lower_bound( X+1,X+1+m,l[i] )-X;
            int right=lower_bound( X+1,X+1+m,r[i] )-X;
            update( 1,1,m,left,right,i );
        }
        memset( vis,0,sizeof vis );
        cnt=0;
        query( 1,1,m );
        printf( "%d\n",cnt );
    }

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