POJ2528_Mayor's posters_solution

来源:互联网 发布:淘宝修改店铺名称 编辑:程序博客网 时间:2024/06/06 20:17
Mayor's posters
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 35053 Accepted: 10176

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

Source

Alberta Collegiate Programming Contest 2003.10.18
题目意思,在很长的墙上贴海报,规定海报高度都是跟墙一样高,长度任意,后面贴的海报可以覆盖前面的海报,贴完后询问有几张海报是露在外面的,露出一小部分也算。这个题目与POJ2777_Count color是完全一样的,只是那里是涂色,这里是贴海报,涂色只有很少的几种颜色,把每张海报看成不同的颜色,无非就是颜色多了点。Count Color里初始状态是颜色都为1,这里墙上初始状态是没有任意海报,用个-1来标记下就可以了,第i张海报就涂上第i种颜色。
但是仔细一看,这里的墙实在有点宽,竟然达到了10^7,如果直接模拟出10^7个点线段树,那内存肯定要爆了。但幸好海报张数是有限的,only 10^4,这里就要引进一个离散化的概念。因为所有海报的起点和终点都是已知的,我们可以把所有海报的起点和终点信息排个序,再去掉重合的点,那么我们就可以以相邻两个点为一个叶子节点来建立一颗线段树,任意一个叶子节点管理的是细分后最小的一个区间。
比如对于这个例子:
1 4 2 6 8 10 3 4 7 10
我们把这些点排序去重后剩下:
1 2 3 4 6 7 8 10
那么我们可以以这些区间里建树:

树根管理的节点[1,8],管理的区间对应为interval[1]-interval[8],即[1,10];左子树管理的节点[1,4],管理的区间为interval[1]-interval[4]即[1,4];右子树管理的节点为[5,8],管理的区间为interval[5]-interval[8]即[6,10]。我们看到[4,6]这个区间就没有了,如果出现要更新[4,6]这个区间的信息怎么办?实际上并不会引起信息丢失,因为它会下降到管理[4,4][6,6]这两个叶子节点,并对这两个叶子节点的颜色进行更新。所以这样建立的树可以保存和更新所有区间的信息。

接下来就只有贴代码了。离散化的思维,大家可以多思考一下,颇有借鉴意义。

#include<stdio.h>#include<algorithm>#include<string.h>using namespace std;struct treeInfo//线段树结构体{int left,right;//管理区间int type;//表示贴的是哪张海报};struct postInfo//海报的起点,终点信息{int start,end;};postInfo post[10005];//最多一万张海报int interval[21000],visible[10005];//interval存储的是所有海报的起点和终点排序去重后的点,最多两万个点;visible记录某种海报是否可见,最多一万张treeInfo segTree[80000];//以interval区间来建树的线段树int t,n,i,j,pointNum,total;//t是caseNum,n是海报张数,pointNum是interval里的有效点个数,total表示最终有几张海报可见void buildTree(int l,int r,int pos)//建树的时候可以不理会区间信息{segTree[pos].left=l;segTree[pos].right=r;segTree[pos].type=-1;//没有海报if(l==r)return;int mid=(l+r)/2;buildTree(l,mid,pos<<1);buildTree(mid+1,r,pos<<1|1);}void update(int l,int r,int pos,int type)//给l,r区间贴上标记为type的海报{int left=segTree[pos].left,right=segTree[pos].right;if(interval[left]==l&&interval[right]==r)//这个要比较的是interval[]的值与传进来的参数{segTree[pos].type=type;//如果完全覆盖,那么更新海报种类,并返回return;}int mid=(left+right)/2;if(segTree[pos].type>0)//这是父节点的信息下降{segTree[pos<<1].type=segTree[pos].type;segTree[pos<<1|1].type=segTree[pos].type;segTree[pos].type=-1;}if(r<=interval[mid])update(l,r,pos<<1,type);else if(l>=interval[mid+1])update(l,r,pos<<1|1,type);else{update(l,interval[mid],pos<<1,type);update(interval[mid+1],r,pos<<1|1,type);}}void query(int l,int r,int pos)//询问l,r区间的海报种类{if(segTree[pos].type>0)//遇到了一种海报{visible[segTree[pos].type]=1;//把相应的海报标记一下,表示出现过return;}if(l==r)//到达叶子节点,返回return;int mid=(segTree[pos].left+segTree[pos].right);query(l,mid,pos<<1);//查询左子树query(mid+1,r,pos<<1|1);//查询右子树}int main(){scanf("%d",&t);while(t--){scanf("%d",&n);for(i=1;i<=n;i++)//输入海报信息,并把所有海报的起点和终点存在interval数组{scanf("%d%d",&post[i].start,&post[i].end);interval[2*(i-1)+1]=post[i].start;interval[2*(i-1)+2]=post[i].end;}sort(interval+1,interval+2*n+1);//对interval排序pointNum=unique(interval+1,interval+2*n+1)-(interval+1);//interval去重,pointNum是去重后留下的元素个数buildTree(1,pointNum,1);//以interval有效元素来建树for(i=1;i<=n;i++)//把每张海报贴上去update(post[i].start,post[i].end,1,i);memset(visible,0,sizeof(visible));//初始化,所有海报都不可见query(1,pointNum,1);//查询只有一次,查询所有可见的海报数量total=0;//海报出现的数量for(i=1;i<=n;i++){if(visible[i])//第i种海报可见total++;}printf("%d\n",total);}return 0;}/*251 42 68 103 47 10*/


 

原创粉丝点击