poj2528 - Mayor's posters - 线段树离散化(详解)

Mayor's posters

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 79035   Accepted: 22736

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:

  • 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

Source

Alberta Collegiate Programming Contest 2003.10.18

思路:

离散化

可以看出他给的1e+7的区间范围太大了,硬刚的话就是tle或者mle,所以用到了离散化的思想,具体步骤如下:

把左右端点入队,排序后去重,然后在数组里找到大于等于左右端点的第一个值,返回它的位置,作为它的新的区间范围,代码如下:

int k=0;
for(int i=1;i<=n;i++){
    scanf("d%d",&left[i],&right[i]);
    v[k++]=left[i];
    v[k++]=right[i];
}
sort(v,v+k);
int n=unique(v,v+k)-v;//表示新数组大小,如果用vector不可以-v这样写
for(int i-1;i<=n;i++){
    int L=lower_bound(v,v+n,left[i])-v+1;//如果指针在v[0]的位置,-v后得0,加1表示左端点是1
    int R=lower_bound(v,v+n,right[i])-v+1;
}

比如[1,200],[50,80],[80,250]

先入队:1,200,50,80,80,250

排序:1,50,80,80,200,250

去重:1,50,80,200,250

这时候重新判断区间的范围:

[1,200]=》[1,4]

[50,80]=》[2,3]

[80,250]=》[3,5]

解题思路

这个题每次张贴一张海报,新的覆盖旧的,问最后又多少张海报会露出来,可见没法用线段树的push_up操作,我们在染色时,就是让线段树中对应一个区间的节点做一个颜色标记,然后push_bown,向下染色,查询的时候,用hash的思想,我开了一个use数组来表示这个颜色计算过没有,我们查询的是整个区间,所以在查询的过程中,如果一个节点的颜色没有被计算进去,则ans++,这时候use[color]=1,标记这个颜色计算过,将不再重复计算。

注意

区间范围啊啊啊,因为区间范围wa了N次,(我也纳闷为啥不是re而是wa),我们用离散化的时候,最悲观的情况是输入的2*N个区间端点没有一个重复的,那么就相当于点是2*N个,所以数组范围有在2*N*4也就是N<<3

代码如下:

#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int N=10010;
int aa[N],bb[N],ans;
int tree[N<<3],use[N<<3];
int v[2*N];

void push_down(int rt){
    if(tree[rt]!=-1){
        tree[rt<<1]=tree[rt<<1|1]=tree[rt];
        tree[rt]=-1;
    }
}
void update(int L,int R,int c,int l,int r,int rt){
    if(L<=l&&R>=r){
        tree[rt]=c;
        return ;
    }
    push_down(rt);
    int m=(l+r)>>1;
    if(L<=m)update(L,R,c,lson);
    if(R>m)update(L,R,c,rson);
}

void query(int l,int r,int rt){
    if(tree[rt]!=-1){
        if(!use[tree[rt]])ans++;
        use[tree[rt]]=1;
        return ;
    }
    int m=(l+r)>>1;
    push_down(rt);
    query(lson);
    query(rson);
}

int main(){
    int t,m;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&m);
        int k=0;
        memset(v,0,sizeof(v));
        for(int i=0;i

 

你可能感兴趣的:(线段树)