POJ2528:Mayor's posters(线段树区间更新+离散化)
DescriptionThe 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
题意:给每个区间贴纸,后面贴的会覆盖前面贴的,问最后能看到的纸有几张
思路:很明显的线段树区间更新问题,但是由于数目大,所以我们要考虑离散化,由于之前没有弄过离散化,看了人家的代码,再加上自己的演草纸上模拟过程,终于弄懂了离散的原理。
首先,我们将区间存放在一个map数组之中,通过s的结构体,我们可以将每个点,与其相对应的区间序号整理起来,然后排序,为了方便判断,将左区间记为负数
通过S,我们重新将数据存入map数组之中,这次map数组存放的是他们位置的区间,由于n只有10000,所以位置最大也就只有10000位,如果存数值则要10000000的空间,泽阳无论在空间还有时间上都得到了优化
例如样例中输入后
排序:1,2,3,4,6,7,8,10
对应位置:1,2,3,4,5,6,7,8
这样我们可以看到,以位置来建树只需要8个空间,但是如果用数值大小来建树则需要10个空间,在当位置与数字的大小差很大的时候,存放位置能优化更多的时间与空间
而现在,map数组中存放的是
1,4
2,5
7,8
3,4
6,8
可以发现,这些位置所对应的数字便是原本题目给出的数字区间,所以我们最后只要求出这些位置覆盖后有几个可见即可
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int n,cnt; const int maxn = 10000+10; struct node { int l,r,n;//n统计颜色 } a[maxn<<2]; struct kode { int point,num;//point记录区间的边,num记录位置 } s[maxn<<2]; int map[maxn<<1][2],ans,flag[maxn<<1]; int cmp(kode x,kode y) { return x.point<y.point; } void init(int l,int r,int i)//建树 { a[i].l = l; a[i].r = r; a[i].n = 0; if(l!=r) { int mid = (l+r)>>1; init(l,mid,2*i); init(mid+1,r,2*i+1); } } void insert(int i,int l,int r,int m) { if(a[i].l == l && a[i].r == r)//找到了区间,更新这个区间的颜色 { a[i].n = m; return; } int mid = (a[i].l+a[i].r)>>1; if(a[i].n>0)//重点注意,如果这个区间被访问了,并且这个区间有颜色,就要将这个区间的颜色更新到其左右孩子的节点,并且要将这个区间的颜色清空,这样才能算是覆盖 { a[2*i].n = a[2*i+1].n = a[i].n; a[i].n = 0; } if(l>=a[2*i+1].l) insert(2*i+1,l,r,m); else if(r<=a[2*i].r) insert(2*i,l,r,m); else { insert(2*i,l,mid,m); insert(2*i+1,mid+1,r,m); } } void solve(int i) { if(a[i].n)//如果有这个区间有颜色了,马上停止访问并返回,因为下面的无论有没有颜色都是已经被覆盖的了 { if(!flag[a[i].n])//易做图有颜色且没被统计过的,就统计一次 { ans++; flag[a[i].n] = 1; } return; } solve(2*i); solve(2*i+1); return; } int main() { int t,i,j; scanf("%d",&t); while(t--) { scanf("%d",&n); for(i = 0; i<n; i++)//离散化 { scanf("%d%d",&map[i][0],&map[i][1]); s[2*i].point = map[i][0]; s[2*i+1].point = map[i][1]; s[2*i].num = -(i+1); s[2*i+1].num = i+1; } sort(s,s+2*n,cmp); int tmp = s[0].point,cnt = 1; for(i = 0; i<2*n; i++) { if(tmp != s[i].point)//如果和前面的不同,这迭代加1 { cnt++; tmp = s[i].point; } if(s[i].num<0) map[-s[i].num-1][0] = cnt; else map[s[i].num-1][1] = cnt; } init(1,cnt,1); for(i = 0; i<n; i++) insert(1,map[i][0],map[i][1],i+1); memset(flag,0,sizeof(flag)); ans = 0; solve(1); printf("%d\n",ans); } return 0; }
补充:软件开发 , C++ ,