POJ - 2528 D - Mayor's posters 区间覆盖+区间不同颜色个数+离散化

Mayor's posters

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 73819   Accepted: 21286

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

 

题意

给出n(n<=10000)个海报[l,r]   1<=l<=r<=10000000

以前的海报会被之后的海报给覆盖,问最后能看到多少张海拔。

 

题解

朴素想法 :

对于每一个海报,对其区间进行染色,最后查询整个区间有多少种颜色

时间复杂度O(n*sigma([l,r]))  显然tle

 

线段树思路:

对于每个海报,利用线段树区间更新O(log(n))

最后查询的时候O(n)

 

这里就非常抽象的区间更新,墙的长度为建立线段树的总区间,每贴一张海报代表将这个区间的颜色涂为相应的,每张海报的颜色当然

都不相同,求最后又多少种颜色就行,但这里还要用到基础的离散化

离散化是把无限空间中无限的个体映射到有限的空间中去,以此提高算法的时空效率。

简单点说,假设区间长度有一亿甚至跟多,但是区间里具体的值却最多只用到了一百万,且不说能否开那么大的数组,也造成了

内存的浪费,所以用离散化来节省不必要的浪费

举这个题目的样例来说(前三个)

如果只是改变区间1 7    2 6    8 10的颜色,那么剩下的数字并没有用到

那么我们将这些数字排序,x[1]=1 x[2]=2 x[3]=6 x[4]=7 x[5]=8 x[6]=10

但是如果每个相邻的差值大于1的时候要插入一个数(就插入x[i]-1好了),

(如果不插的话

 假设三张海报为:1 10   1 4   6 10

离散化时 x[1] = 1   x[2]=4  X[3]=6   X[4]=10
第一张海报时:墙的1~4被染为1;
第二张海报时:墙的1~2被染为2,3~4仍为1;
第三张海报时:墙的3~4被染为3,1~2仍为2。
最终,第一张海报就显示被完全覆盖了,然后输出2,但是正确答案明显是3)

插入后新的排序为x[1]=1 x[2]=2 x[3]=5 x[4]=6 x[5]=7 x[6]=8 x[7]=9 x[8]=10

然后以这个新的长度为8的数组区间建树就好

 

类似于这样区间染色的不需要lz数组,只需要用color数组来表示即可, 0或者-1表示该区间没有颜色或者很多颜色

利用了懒惰数组的特性来解决区间染色问题.

 

本题用了color数组表示该区间的颜色,0表示该区间没有颜色或者有很多颜色.

查询时遇到0的时候需要向下继续搜索,说明在其的子区间还可能有被覆盖的颜色.

查询到非0的时候,说明该区间都是该颜色,直接返回即可.

 

代码:

#define poj
#ifdef poj
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
#include <string>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
using namespace std;
typedef long long ll;
const int maxn = 1e4+10;
int ans;
struct SegTree {
    int color[maxn<<4];
    bool vis[maxn];
    void init() {
        memset(color,0,sizeof(color));
        memset(vis,0,sizeof(vis));
        ans = 0;
    }
    void push_down(int rt) {
        if(!color[rt]) return;
        color[rt<<1] = color[rt<<1|1] = color[rt];
        color[rt] = 0;
    }
    void update(int ql,int qr,int val,int l,int r,int rt) {
        if(ql == l && qr == r) {
            color[rt] = val;
            return;
        }
        push_down(rt);
        int mid = (l + r) >> 1;
        if(qr <= mid) update(ql,qr,val,l,mid,rt<<1);
        else if(ql > mid) update(ql,qr,val,mid+1,r,rt<<1|1);
        else {
            update(ql,mid,val,l,mid,rt<<1);
            update(mid+1,qr,val,mid+1,r,rt<<1|1);
        }
    }
    void query(int l,int r,int rt) {
        if(color[rt]) {
            if(!vis[color[rt]]) vis[color[rt]] = 1,ans++;
            return ;
        }
        if(l == r) return ;
        push_down(rt);
        int mid = (l + r) >> 1;
        query(l,mid,rt<<1);
        query(mid+1,r,rt<<1|1);
    }
}seg;
struct node {
    int l,r;
}Seg[maxn];
int arr[maxn<<3];
int main()
{
    int caset;scanf("%d",&caset);
    while(caset--)
    {
        seg.init();
        int n;scanf("%d",&n);
        int cnt = 0;
        for(int i=0;i<n;i++) {
            scanf("%d%d",&Seg[i].l,&Seg[i].r);
            arr[++cnt] = Seg[i].l;arr[++cnt] = Seg[i].r;
        }
        sort(arr+1,arr+cnt+1);
        int tot = 1;
        for(int i=2;i<=cnt;i++) { /// 去重
            if(arr[i] != arr[i-1]) arr[++tot] = arr[i]; 
        }
        cnt = tot;
        for(int i=2;i<=cnt;i++) { /// 优化离散化 避免错误覆盖
            if(arr[i] > arr[i-1] + 1) arr[++tot] = arr[i]-1;
        }
        sort(arr+1,arr+tot+1);
        //for(int i=1;i<=tot;i++) printf("%d ",arr[i]);printf("\n");
        for(int i=0;i<n;i++) {
            int l = lower_bound(arr+1,arr+tot+1,Seg[i].l) - arr;
            int r = lower_bound(arr+1,arr+tot+1,Seg[i].r) - arr;
            seg.update(l,r,i+1,1,tot,1);
        }
        seg.query(1,tot,1);
        printf("%d\n",ans);
    }
    return 0;
}

 

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_38013346/article/details/80342860
个人分类: 线段树
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭