poj 2528 Mayor's posters 線段樹成段更新+離散化

題目:

Mayor’s posters
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 67336 Accepted: 19470

Description

The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral posters at all places at their whim. The city council has finally decided to build an electoral wall for placing the posters and introduce the following rules:
Every candidate can place exactly one poster on the wall.
All posters are of the same height equal to the height of the wall; the width of a poster can be any integer number of bytes (byte is the unit of length in Bytetown).
The wall is divided into segments and the width of each segment is one byte.
Each poster must completely cover a contiguous number of wall segments.

They have built a wall 10000000 bytes long (such that there is enough place for all candidates). When the electoral campaign was restarted, the candidates were placing their posters on the wall and their posters differed widely in width. Moreover, the candidates started placing their posters on wall segments already occupied by other posters. Everyone in Bytetown was curious whose posters will be visible (entirely or in part) on the last day before elections.
Your task is to find the number of visible posters when all the posters are placed given the information about posters’ size, their place and order of placement on the electoral wall.

Input

The first line of input contains a number c giving the number of cases that follow. The first line of data for a single case contains number 1 <= n <= 10000. The subsequent n lines describe the posters in the order in which they were placed. The i-th line among the n lines contains two integer numbers li and ri which are the number of the wall segment occupied by the left end and the right end of the i-th poster, respectively. We know that for each 1 <= i <= n, 1 <= li <= ri <= 10000000. After the i-th poster is placed, it entirely covers all wall segments numbered li, li+1 ,… , ri.

Output

For each input data set print the number of visible posters after all the posters are placed.

The picture below illustrates the case of the sample input.
這裏寫圖片描述

Sample Input

1
5
1 4
2 6
8 10
3 4
7 10

Sample Output

4

Source

Alberta Collegiate Programming Contest 2003.10.18


題意:

在一個長方形的區域內貼海報,每個海報的高度都和區域高度相等。
給出海報的位置,要你告訴多少海報至少有一部分露在外面。


解法1:

如果一個海報i完全被蓋住,那麼一定有在它後面貼的海報能夠將其完全覆蓋。
也就是說如果先在線段樹裏面把後面的海報覆蓋的區域表示出來,那麼查詢海報i覆蓋的區域會發現,該區域正好完全覆蓋。那麼露在外面的海報數減1。
因爲區域太寬,但是n不超過1W,故離散化。

補充一個,之前的代碼是混過去的,數據不強,有個小問題已作
更正。
對於 [1,5] [1,2] [4,5] 這組數據,應該離散化爲[1,5] [1,2] [4,5]
而不是[1,4] [1,2] [3,4] 否則會出錯。

原因就是如果兩個排序後相鄰數離散化之前的差值大於1,那麼在離散化時必須要在他們中間加1個數,讓他們離散化後的仍大於1(實際爲2)。


代碼:

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

#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define lson  (ind<<1)
#define rson  (ind<<1|1)
#define MID   int mid=(le+ri)>>1
const int maxn=10000;

int n,border;
struct SEG
{
    int le,ri;
}seg[maxn+10];

struct A
{
    int ind,val;
    bool operator<(const A c)const
    {
        return val<c.val;
    }
}a[2*maxn+10];

void cope()//離散化
{
    sort(a,a+2*n);

    int nex=1;

    for0(i,2*n)
    {
        int ret;
        if(!i)  ret=nex++;
        else if(a[i].val!=a[i-1].val)
        {
            if(a[i].val-a[i-1].val>1) nex++;
            ret=nex++;
        }
        else ret=nex-1;

        int p=a[i].ind/2;
        if(a[i].ind&1) seg[p].ri=ret;
        else           seg[p].le=ret;
    }
    border=nex-1;

}
struct Node
{
    int le,ri,sum,lazy;
    void update()
    {
        sum=ri-le+1;
        lazy=1;
    }
};
struct SegMentTree
{
    Node C[16*maxn];
    void build(int ind ,int le,int ri)
    {
        C[ind].le=le,C[ind].ri=ri,C[ind].lazy=0; C[ind].sum=0;
        if(le==ri) return;

        MID;
        build(lson,le,mid);
        build(rson,mid+1,ri);
    }

    void pushDown(int ind)
    {
        if(C[ind].lazy)
        {
            C[lson].update();
            C[rson].update();
            C[ind].lazy=0;
        }
    }
    int query(int ind,int L,int R)
    {
        int le=C[ind].le,ri=C[ind].ri;
        if(L<=le&&ri<=R)
        {
            int ans=C[ind].sum;
            C[ind].update();
            return ans;
        }
        pushDown(ind);
        MID;
        int ans=0;
        if(L<=mid) ans+=query(lson,L,R);
        if(R>mid)  ans+=query(rson,L,R);

        C[ind].sum=C[lson].sum+C[rson].sum;
        return ans;

    }
}sgt;
void solve()
{
    sgt.build(1,1,border);
    int ans=n;
    for(int i=n-1;i>=0;i--)
    {
        int L=seg[i].le,R=seg[i].ri;
        int cnt=sgt.query(1,L,R);
        if(cnt==R-L+1)  ans--;

    }
    printf("%d\n",ans);
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for0(i,n)
        {
            scanf("%d%d",&a[2*i].val,&a[2*i+1].val);
            a[2*i].ind=2*i; a[2*i+1].ind=2*i+1;
        }
        cope();
        solve();
    }

    return 0;
}

解法2:

參考網上的解法。對於線段樹中le==ri的結點只需標記color即可。
假設每張海報都具有不同的顏色,線段樹維護了一個區域的情況。那麼最後只需統計線段樹中有多少不同顏色即可。因爲query的本質是二分,所以在O(LlogL)的時間內一定能找到。

對於ri-le>1的結點,color值相當於是延遲標記。
這樣表示只會用到pushDown操作,而用不到pushUp。

當一個延遲標記用過一次後,記得取消這個標記。


代碼:

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

#define mem(a,x)  memset(a,x,sizeof a)
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define lson  (ind<<1)
#define rson  (ind<<1|1)
#define MID   int mid=(le+ri)>>1
const int maxn=10000;

int n,border;
struct SEG
{
    int le,ri;
}seg[maxn+10];

struct A
{
    int ind,val;
    bool operator<(const A c)const
    {
        return val<c.val;
    }
}a[2*maxn+10];
bool vis[maxn+5];
void cope()//離散化
{
    sort(a,a+2*n);

    int nex=1;

    for0(i,2*n)
    {
        int ret;
        if(!i)  ret=nex++;
        else if(a[i].val!=a[i-1].val)
        {
            if(a[i].val-a[i-1].val>1) nex++;
            ret=nex++;
        }
        else ret=nex-1;

        int p=a[i].ind/2;
        if(a[i].ind&1) seg[p].ri=ret;
        else           seg[p].le=ret;
    }
    border=nex-1;

}
struct Node
{
    int le,ri,color;
    void update(int &c)
    {
        color=c;
    }
};
struct SegMentTree
{
    Node C[16*maxn];
    void build(int ind ,int le,int ri)
    {
        C[ind].le=le,C[ind].ri=ri,C[ind].color=0;
        if(le==ri) return;

        MID;
        build(lson,le,mid);
        build(rson,mid+1,ri);
    }

    void pushDown(int ind)
    {
        if(C[ind].color)
        {
            C[lson].update(C[ind].color);
            C[rson].update(C[ind].color);
            C[ind].color=0;//如果不取消,會重複更新子結點,造成錯誤。很重要。
            //對於C[ind].le!=C[ind].ri的結點,C[ind].color相當於是一種特殊的延遲標記。
        }
    }
    void update(int ind,int L,int R,int c)
    {
        int le=C[ind].le,ri=C[ind].ri;
        if(L<=le&&ri<=R)
        {
            C[ind].update(c);
            return;
        }
        pushDown(ind);
        MID;

        if(L<=mid) update(lson,L,R,c);
        if(R>mid)  update(rson,L,R,c);

    }
    int query(int ind,int L,int R)
    {
        int le=C[ind].le,ri=C[ind].ri;
        if(le==ri)
        {
            int tc=C[ind].color;
            if(tc&&!vis[tc])
            {
                vis[tc]=1;
                return 1;
            }
            return 0;
        }
        pushDown(ind);
        MID;
        return query(lson,le,mid)+query(rson,mid+1,ri);

    }
}sgt;
void solve()
{
    sgt.build(1,1,border);
    for0(i,n)
    {
        int L=seg[i].le,R=seg[i].ri;
        sgt.update(1,L,R,i+1);
    }
    mem(vis,0);
    printf("%d\n",sgt.query(1,1,border));
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for0(i,n)
        {
            scanf("%d%d",&a[2*i].val,&a[2*i+1].val);
            a[2*i].ind=2*i; a[2*i+1].ind=2*i+1;
        }
        cope();
        solve();
    }

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