Mayor's posters
POJ - 2528- 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.
The picture below illustrates the case of the sample input.
1 5 1 4 2 6 8 10 3 4 7 10Sample Output
4
看到网上博客写的很好直接粘这了
题意:先输入case数,每个case输入n,表示下面有n个海报,每行就是海报的左右坐标,第i个海报的颜色为i。一面墙长度固定为10000000,问这些海报贴上去后能看到多少种颜色
这个问题的难处其实是怎么离散化(也就是映射,映射后就是简单的线段树整段更新,最后区间询问)。
int s[MAXN][2]; 保存原始的数据,[0]是起点坐标,[1]是终点坐标,那么一共产生2*n个端点
struct point
{
int a,n,f; //端点坐标,属于哪条线段,起点或者终点
}p[2*MAXN];
所以把2*n个端点逐一放入p数组中,并且要记录这个端点是来自哪条线段(n这个域),在这条线段中是起点还是终点(f这个域)
然后对p数组排序,以端点坐标大小排序(a这个域)
接下来是映射,例如排序后的结果为
10,21,38,40,40,59
映射为
1,2,3,4,4,5
也就是说按数字大小映射,而且也可以发现,最后的5其实也代表了有多少个不同的数字
这个映射的结果一定包含[1,m]的所有整数,等下我们要建线段树的时候,总区间的长度就是[1,m]
m最大可以去到80000(60000也行),80000怎么来的,是2*10000*4
因为海报的个数最多10000,有20000个端点,极端情况下,这20000个点都不一样,映射过去的话,就是[1,20000],也就是m最大可以是m
回想一般情况下,线段树的总区间为[1,m]的话,我们开辟线段树的数组一般为4*m(其实开到3*m就足够了),所以这就是为什么80000的原因
说回头,我们扫过p数组的时候,每得到一个点,就先映射它的坐标(和它前面那个端点坐标比较是否不同,不同的话,就是一个新的点,具体看代码),然后看它是来自哪条线段(映射后同样是这条线段),再看它在原线段中是起点还是终点,然后相对应地记录现在线段的起点和终点
最后映射后的线段信息全部在下面的数组中
struct interval //离散化后的线段
{
int l,r,col;
}in[MAXN];
得到了它,就可以建树,整段更新,查询了
code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 10010
using namespace std;
bool used[MAXN];//查询时记录哪些颜色已经被计数
int s[MAXN][2],N;//s数组记录原始数组
struct point{
int a,n,f;//端点坐标,属于哪条线段,起点或者终点
}p[2*MAXN];
struct interval{//离散化后的线段
int l,r,col;
}in[MAXN];
struct segment{//线段树节点
int l,r,col,val;//val表示这个区间是否已经有一张海报完全覆盖
}Tree[MAXN*8];
int query(int l,int r,int rt){
int col = Tree[rt].col;
if(Tree[rt].val){
if(!used[col]){
used[col] = 1;
return 1;
}
else
return 0;
}
int mid = Tree[rt].l + Tree[rt].r >> 1;
return query(l,mid,rt<<1) + query(mid+1,r,rt<<1|1);
}
void update(int l,int r,int col,int rt){
if(Tree[rt].val && Tree[rt].col == col)
return;
if(Tree[rt].l == l && Tree[rt].r == r){
Tree[rt].col = col;
Tree[rt].val = 1;
return;
}
if(Tree[rt].val){
Tree[rt<<1].val = Tree[rt<<1|1].val = Tree[rt].val;
Tree[rt<<1].col = Tree[rt<<1|1].col = Tree[rt].col;
Tree[rt].val = 0;
}
int mid = Tree[rt].l + Tree[rt].r >> 1;
if(l > mid)
update(l,r,col,rt<<1|1);
else if(r <= mid)
update(l,r,col,rt<<1);
else{
update(l,mid,col,rt<<1);
update(mid+1,r,col,rt<<1|1);
}
}
void build(int l,int r,int rt){
Tree[rt].l = l;
Tree[rt].r = r;
Tree[rt].val = 0;
Tree[rt].col = 0;
if(l == r) return;
int mid = l + r >> 1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
}
bool cmp(point x,point y){
return x.a < y.a;
}
int main(){
int Cas;
scanf("%d",&Cas);
while(Cas--){
scanf("%d",&N);
//离散化
for(int i = 1; i <= N; i++){
scanf("%d%d",&s[i][0],&s[i][1]);
p[2*i-1].a = s[i][0];
p[2*i-1].n = i;
p[2*i-1].f = 0;
p[2*i].a = s[i][1];
p[2*i].n = i;
p[2*i].f = 1;
}
sort(p+1,p+2*N+1,cmp);
p[0].a = p[1].a;
int m = 1,n,f;
for(int i = 1; i <= 2*N; i++){
n = p[i].n;
f = p[i].f;
if(p[i].a != p[i-1].a) m++;
if(!f){
in[n].l = m;
in[n].col = n;
}
else{
in[n].r = m;
in[n].col = n;
}
}
//离散化结束
build(1,m,1);
for(int i = 1; i <= N; i++){
update(in[i].l,in[i].r,in[i].col,1);
}
memset(used,0,sizeof(used));
printf("%d\n",query(1,m,1));
}
return 0;
}