POJ2528,线段树+离散化

来源:互联网 发布:php相册源码 编辑:程序博客网 时间:2024/05/17 00:55

题目链接:

POJ2528

Mayor's posters
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 50574 Accepted: 14658

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

151 42 68 103 47 10

Sample Output

4
题意:
候选者在展览板上贴海报,当所有人都贴完了,有多少海报是可以被看见的(看见,可以是整幅海报都可以被看见,或者是海报的一部分可以被看见)
题解:
我觉得这道题目需要注意的是,(拿样例来说)区间[1,4],1和4不是点(可以看图)是某一块小展览板;
在离散化的时候,需要注意:(看不懂下面的话,可以先看程序,手推一组样例,然后再来理解这段话)
1 3 4 5 9一般程序对应于1 2 3 4 5(这样会导致不相邻的线段变为相邻)实际应该对应于1 3 4 5 7
线段树+离散化 就OK了
//bei#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define Maxn 12000int tol[Maxn<<4],segT[Maxn<<4],li[Maxn],ri[Maxn];//tol是用来保存所有区间的左右端点,segT是建树用的数组,li是保存区间左端点,ri是保存对应右端点bool vis[Maxn]; //用来标记哪些颜色已经统计过了int ans;int Binsearch(int key,int r,int tol[]) //二分查找位置,返回的位置就是离散化后的值{    int l = 1,m;    while (l <= r)    {        m = (l+r) >> 1;        if (tol[m] > key)            r = m - 1;        else if (tol[m] < key)            l = m + 1;        else            return m;    }}void PushDown(int rt) // 线段树的延迟更新{    if (segT[rt])    {        segT[rt<<1] = segT[rt<<1|1] = segT[rt];        segT[rt] = 0;    }}void update(int L,int R,int color,int l,int r,int rt) // 将对应区间的值更新为color,表示该段区间贴的海报{    if (L <= l && r <= R)    {        segT[rt] = color;        return ;    }    PushDown(rt); // 当该区间被贴上另外的海报时,需要向下更新!    int m = (l+r) >> 1;    if (L <= m)        update(L,R,color,lson);    if (R > m)        update(L,R,color,rson);}void query(int l,int r,int rt){    if (segT[rt])// 举个例子:区间[4,6]贴的是同一幅海报,假设对应color的值为2,在线段树中[4,6] 是两段区间[4,5]和[6],当统计完[4,5]之后,再统计到[6]时就不能在加一了//所以得用一个vis数组用来标记哪些颜色已经被统计过了    {        if (!vis[segT[rt]])        {            ++ans;            vis[segT[rt]] = true;        }        return ;    }    if (l == r) return ;    int m = (l+r) >> 1;    query(lson);    query(rson);}int main(){    int c,n,i,k;    while (~scanf("%d",&c))    {        while (c--)        {            scanf("%d",&n);            k = 1;            for (i = 1; i <= n; ++i) // tol数组先保存所有区间的端点值            {                scanf("%d%d",&li[i],&ri[i]);                tol[k++] = li[i];                tol[k++] = ri[i];            }            sort(tol+1,tol+k); // 排序            int m = 2;            for (i = 2; i < k; ++i) // 去掉tol数组中重复的值,因为在二分查找位置时,不能一个值可以映射成两个位置,对吧!            {                if (tol[i] != tol[i-1])                    tol[m++] = tol[i];            }            for (i = m - 1; i > 1; --i)//这步+下面的排序一起理解,目的是将原本不相邻的区间也离散成不相邻的区间(可以手推一组样例,就好理解了)            {                if (tol[i] != tol[i-1]+1)                    tol[m++] = tol[i-1] + 1;            }            sort(tol+1,tol+m);            memset(segT,0,sizeof(segT));            for (i = 1; i <= n; ++i)            {                int a = Binsearch(li[i],m-1,tol);//得到该区间左端点离散后的值                int b = Binsearch(ri[i],m-1,tol);                update(a,b,i,1,m-1,1);//建树,其中这段区间对应的海报color值为i,正好保证了每幅海报是不相同的            }            ans = 0;            memset(vis,false,sizeof(vis));            query(1,m-1,1); //查询,记得写上上面两条语句;            printf("%d\n",ans);        }    }    return 0;}

0 0
原创粉丝点击