hihoCoder #1079 : 离散化

#1079 : 离散化

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

小Hi和小Ho在回国之后,重新过起了朝7晚5的学生生活,当然了,他们还是在一直学习着各种算法~

这天小Hi和小Ho所在的学校举办社团文化节,各大社团都在宣传栏上贴起了海报,但是贴来贴去,有些海报就会被其他社团的海报所遮挡住。看到这个场景,小Hi便产生了这样的一个疑问——最后到底能有几张海报还能被看见呢?

于是小Ho肩负起了解决这个问题的责任:因为宣传栏和海报的高度都是一样的,所以宣传栏可以被视作长度为L的一段区间,且有N张海报按照顺序依次贴在了宣传栏上,其中第i张海报贴住的范围可以用一段区间[a_i, b_i]表示,其中a_i, b_i均为属于[0, L]的整数,而一张海报能被看到当且仅当存在长度大于0的一部分没有被后来贴的海报所遮挡住。那么问题就来了:究竟有几张海报能被看到呢?

提示一:正确的认识信息量

提示二:小Hi大讲堂之线段树的节点意义

输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第1行为两个整数N和L,分别表示总共贴上的海报数量和宣传栏的宽度。

每组测试数据的第2-N+1行,按照贴上去的先后顺序,每行描述一张海报,其中第i+1行为两个整数a_i, b_i,表示第i张海报所贴的区间为[a_i, b_i]。

对于100%的数据,满足N<=10^5,L<=10^9,0<=a_i<b_i<=L。

输出

对于每组测试数据,输出一个整数Ans,表示总共有多少张海报能被看到。

样例输入
5 10
4 10
0 2
1 6
5 9
3 4
样例输出
5
题目链接:http://hihocoder.com/problemset/problem/1079

题意:n张海报按顺序粘贴,每张海报粘贴的位置为[ai,bi],问最后在墙上[0,L]能看到多少张海报。
思路:因为n只有105,而粘贴区间却有109。首先离散化海报的张贴区间。然后利用线段树区间更新来更新粘贴区间。注意:
由于海报的粘贴区间是非离散化的数据,即是连续的。所以[l,r]必须分解成[l,mid][mid,r]。这是与离散型数据的区别,
离散型数据的区间[l,r]分解成[l,mid][mid+1,r]。
例如这样一种数据:
3 4
1 4
1 2
3 4
如果按照离散型数据来二分区间的话,最后只能是有2张海报。1,2是一张,3,4是第二张,并没有考虑2~3的情况。
按照连续性的数据来二分的花,就可以是1~2,2~3,3~4。
其实按照离散型数据来二分区间也是可以的,只需要把[ai,bi]变成[ai*2,bi*2]就可以了。
TL中unique的函数 unique的功能是去除相邻的重复元素(只保留一个),不是真正把重复的元素删除,其实是,该函数把重复的元素一到后面去了,然后依然保存到了原数组中,然后返回去重后最后一个元素的地址,因为unique去除的是相邻的重复元素,所以一般用之前都会要排一下序。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=1e6+100;
int l[MAXN],r[MAXN],c[2*MAXN];
int lazy[MAXN];
int date[MAXN];
int compress(int n)
{
    memcpy(c,l,sizeof(l));
    memcpy(c+n,r,sizeof(r));
    sort(c,c+2*n);
    int size=unique(c,c+2*n)-c;
    for(int i=0; i<n; i++)
    {
        l[i]=lower_bound(c,c+size,l[i])-c+1;
        r[i]=lower_bound(c,c+size,r[i])-c+1;
        l[i]*=2;
        r[i]*=2;
    }
    return size;
}
void pushdown(int l,int r,int pos)
{
    if(lazy[pos]==0) return;
    int mid=(l+r)<<1;
    lazy[pos<<1]=lazy[pos];
    lazy[pos<<1|1]=lazy[pos];
    lazy[pos]=0;
}
void update(int L,int R,int i,int l,int r,int pos)
{
    if(L<=l&&r<=R)
    {
        lazy[pos]=i;
        return;
    }
    pushdown(l,r,pos);
    int mid=(l+r)>>1;
    if(L<=mid) update(L,R,i,l,mid,pos<<1);
    if(R>mid) update(L,R,i,mid+1,r,pos<<1|1);
}
void query(int l,int r,int pos)
{
    if(l==r)
    {
        date[l]=lazy[pos];
        return;
    }
    pushdown(l,r,pos);
    int mid=(l+r)>>1;
    query(l,mid,pos<<1);
    query(mid+1,r,pos<<1|1);
}
int main()
{
    int i,n,L;
    while(~scanf("%d%d",&n,&L))
    {
        memset(lazy,0,sizeof(lazy));
        memset(c,0,sizeof(lazy));
        for(i=0; i<n; i++)
            scanf("%d%d",&l[i],&r[i]);
        L=compress(n)*2;
        for(i=0; i<n; i++)
        {
            if(l[i]==r[i]) continue;
            update(l[i],r[i],i+1,1,L,1);
        }
        query(1,L,1);
        sort(date,date+2*L+1);
        int ans=unique(date,date+2*L+1)-(date+1);
        cout<<ans<<endl;
    }
    return 0;
}
离散化+线段树区间更新
I am a slow walker,but I never walk backwards.
原文地址:https://www.cnblogs.com/GeekZRF/p/5974410.html