Mayor's posters POJ - 2528(离散化+成段更新+区间统计)

Mayor's posters

POJ - 2528

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 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.
Sample Input
1
5
1 4
2 6
8 10
3 4
7 10
Sample 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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值