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:
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.
- 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 l
i 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 <= l
i <= ri <= 10000000. After the i-th poster is placed, it entirely covers all wall segments numbered l
i, l
i+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.
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
题目意思大概是含1*10^7个单位长度的板上贴海报,每个海报占得地方是l~r的单位长度,因为后面贴的海报可能遮住前面贴的海报,求最后可以露出部分或者全部的海报的数目。
先推荐一篇介绍离散化的文,http://www.cppblog.com/MiYu/archive/2010/10/15/129999.aspx
注意到板含有10^7个单位,若是简单的线段树区间更新会超内存,但是海报的数目只有10000个,这时候就要用离散化进行处理。原来的板的最小区间含一个单位,运用离散化将板分成由几个更大的区间组成的板。
一开始我的离散化想法是把所有的l,r看成端点,把所有区间划分成几部分,例如上例就化成1~2,2~3,3~4,4~6,6~7,7~8,8~10,10~+∞这几个区间,提交结果WA,发现l是可以等于r的- -,那样像这样区间的划分就不成立了。
那么就转为将所有的区间离散化为x[1]=1,x[2]=2,x[3]=3,x[4]=4,x[5]=6,x[6]=7,x[7]=8,x[8]=10这几个点,线段树的最大区间由1~10变成了1~8,第一张海报覆盖了1~4,第二张覆盖了2~5,第三张覆盖了7~8……
但是这样有个问题,要是有三张海报,第一张是1 10,第二张是1~4,第三张是6~10,离散化结果第一张覆盖了1~8,第二张覆盖了1~4,第二张覆盖了5~8,结果就只露出来两张海报,实际第一张也有5这个地方是露出来的。所以还需要一个在相差大于1相邻点间插入一个值的操作。
#include<stdio.h> #include<algorithm> #include<string.h> #include <iostream> #include <functional> #include <vector> using namespace std; #define maxn 40000+10 typedef struct { int l,r,change; }node; node num[maxn<<2]; int vis[10010]; void build(int pos,int L,int R) { num[pos].change=0; num[pos].l=L; num[pos].r=R; if(L==R) return; int mid=(L+R)>>1; build(pos<<1,L,mid); build(pos<<1|1,mid+1,R); } void pushdown(int pos,int L,int R) { if(num[pos].change!=0) { num[pos<<1].change=num[pos<<1|1].change=num[pos].change; num[pos].change=0; } } void update(int pos,int L,int R,int ul,int ur,int val) { if(ul>R||ur<L) return ; if(ul<=L&&ur>=R) { num[pos].change=val; return ; } else { pushdown(pos,L,R); int mid=(L+R)>>1; update(pos<<1,L,mid,ul,ur,val); update(pos<<1|1,mid+1,R,ul,ur,val); } } void query(int pos,int L,int R) { if(L==R) { vis[num[pos].change]=1; return ; } else { pushdown(pos,L,R); int mid=(L+R)>>1; query(pos<<1,L,mid); query(pos<<1|1,mid+1,R); } } int main() { int t,n,x[40010],i,xcount,poster[10010][2],add,l,r,ans; scanf("%d",&t); while(t--) { scanf("%d",&n); ans=xcount=0; memset(x,0,sizeof(x)); memset(vis,0,sizeof(vis)); for(i=1;i<=n;i++) { scanf("%d%d",&poster[i][0],&poster[i][1]); x[xcount++]=poster[i][0]; x[xcount++]=poster[i][1]; } sort(x,x+xcount); xcount=unique(x,x+xcount)-x; //讲所有端点排序并去重复 add=xcount; for(i=1;i<xcount;i++) { if(x[i]!=x[i-1]+1) x[add++]=x[i-1]+1; //在每个相邻端点相差大于1的点间加一个点 } sort(x,x+add); xcount=unique(x,x+add)-x; //加入新坐标后的坐标数组 build(1,1,xcount); for(i=1;i<=n;i++) { l=lower_bound(x,x+xcount,poster[i][0])-x+1; r=lower_bound(x,x+xcount,poster[i][1])-x+1; //查出左右端点的次序 update(1,1,xcount,l,r,i); //更新线段树,每个海报的对应区间标记成海报次序 } query(1,1,xcount); for(i=1;i<=n;i++) { if(vis[i]) ans++; } printf("%d\n",ans); } return 0; }