点我看题目 

题意 :建一堵墙粘贴海报,每个候选人只能贴一张海报,海报的高度与墙一样高,一张海报的宽度是整数个单位,墙被划分为若干个部分,每个部分的宽度为一个单位,每张海报完全的覆盖一段连续的墙体,墙体的宽度占整数个单位。因为候选人将海报贴到墙上的时候可能会将别人的覆盖或覆盖一部分,给出海报的大小,选举墙上张贴的位置,和张贴的次序,然后问你最后还能看到几张海报。

思路 : 这个墙因为有10000000单位长,而n最大有10000,所以要先进行离散化,但是离散化之前要先将数字存起来,排序之后再将每相邻的两个数之间一个数加入离散的数组,离散化的处理 :先将n张海报的左边界,右边界中间位置存储在数组x里,然后递增排序x,剔除其中重复的坐标,可以当成染色问题,就是贴上一张海报就将这张海报染上颜色。

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <algorithm>

const int maxn =  10011 ;

bool vis[maxn] ;//颜色i被使用的标志是vis[i]
int l[maxn],r[maxn],num[maxn*3],tree[maxn*12],x[maxn*3] ;
//不大于左边界的不同坐标数为l[i],不大于右边界的不用坐标数为r[i],左边界的坐标为x[3*i-2],右边界的坐标
//为x[3*i-1],中间坐标为x[3*i]。x数组排序后在x[1...j]中不重复的坐标数为num[i].
int c,n ;
//线段树中结点k标记为tree[k],即代表区间的颜色码


using namespace std ;

int binarysearch(int sum)//计算坐标区间[0...sum]中不同的坐标数
{
    int l = 1 , r = 3*n ;
    while(r >= l)
    {
        int mid = (l+r) >> 1 ;
        if(x[mid] <= sum)
        l = mid+1 ;
        else r = mid-1;
    }
    return num[r] ;
}

void update(int i)
{
    if(!tree[i]) return ;
    tree[i*2] = tree[i*2+1] = tree[i] ;
    tree[i] = 0 ;
}

void change(int tl,int tr,int l,int r,int i,int co)
{
    if(tr < l || tl > r) return ;
    if(tl <= l && r <= tr)
    {
        tree[i] = co ;
        return ;
    }
    update(i) ;
    int mid = (l+r) >> 1 ;
    change(tl,tr,l,mid,i*2,co) ;
    change(tl,tr,mid+1,r,i*2+1,co) ;
}

int require(int l ,int r,int i)
{
    int mid = (l+r) >> 1 ;
    if(tree[i])
    {
        if(!vis[tree[i]])//在节点i已标记的情况下,若当前颜色未先涂过,则置该颜色使用标志并返回1,否则返回0,以防重复标记
        {
            vis[tree[i]] = 1;
            return 1 ;
        }
        return 0 ;
    }
    if(l == r) return 0 ;
    return require(l,mid,i*2)+require(mid+1,r,i+i+1) ;
}

void Init()//离散化处理海报信息
{
    scanf("%d",&n) ;
    for(int i = 1 ; i <= n ;i++)
    {
        scanf("%d %d",&l[i],&r[i]) ;//读入每张海报的左右边界。
        x[i*3-2] = l[i] ; x[i*3-1] = r[i] ;x[i*3] = (l[i]+r[i])>>1 ;
    }
    sort(x+1,x+3*n+1) ;
    memset(num,0,sizeof(num)) ;
    for(int i = 1 ; i <= 3*n ; i++)
    {
        num[i] = num[i-1] ;
        if(x[i] != x[i-1]) num[i]++ ;
    }
    for(int i = 1 ; i <= n ; i++)
    {
        l[i] = binarysearch(l[i]) ;
        r[i] = binarysearch(r[i]) ;
    }
}

void solve()
{
    memset(tree,0,sizeof(tree)) ;//线段树中每个结点代表的区间未涂色
    for(int i = 1 ; i <= n ;i++)
    change(l[i],r[i],1,3*n,1,i) ;
    memset(vis,false,sizeof(vis)) ;
    printf("%d\n",require(1,3*n,1) );
}
int main()
{
    scanf("%d",&c) ;
    for(int i = 1 ; i <= c ; i++)
    {
        Init() ;
        solve() ;
    }
    return 0 ;
}
View Code

 

posted on 2014-02-21 19:24  枫、  阅读(264)  评论(0编辑  收藏  举报