现在的位置: 首页 > 综合 > 正文

【数据结构+线段树】连续型/离散型线段树

2018年04月12日 ⁄ 综合 ⁄ 共 2050字 ⁄ 字号 评论关闭

背景

在线段树的通常用法中,线段树的节点是有2种不同的意义的,

一种是离散型的:一个节点虽然描述的是一个区间[3, 9],但是实际上这样一个区间是{3, 4, 5, 6, 7, 8, 9}这样的意义。

而另一种就是连续型的:一个节点如果描述的是一个区间[3, 9],它就确确实实描述的是在数轴上从3这个标记到9这个标记的这一段。

这两种不同的意义有什么区别呢?

有这样的几个区别:

1.叶子节点:在离散型中,叶子节点是[i, i],而连续性中是[i, i + 1];

2.分解区间:在离散型中,一段区间是分解成为[l, m], [m + 1, r],而在连续型中,是分解成为[l, m], [m, r];3.其他所有类似的判定问题

题目

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

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

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

输入

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

每组测试数据的第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

解法

区间离散化+连续型线段树

代码

#include <iostream>
#include <string.h>
#include <map>
#include <set>
#include <vector>
using namespace std;

int tree[1000000];
void down(int l, int r, int idx){
    if(tree[idx] && l<r){
        tree[idx*2+1] = tree[idx*2+2] = tree[idx];
        tree[idx] = 0;//@error: lost this
    }
}
void _set(int l, int r, int idx, int a, int b, int d){
    if(a<=l && b>=r) { tree[idx] = d; return; }
    int mid = (l+r)/2;
    down(l, r, idx);
    if(a>=mid) _set(mid, r, idx*2+2, a, b, d);
    else if(b<=mid) _set(l, mid, idx*2+1, a, b, d);
    else{
        _set(mid, r, idx*2+2, mid, b, d); // b > mid
        _set(l, mid, idx*2+1, a, mid, d); // a < mid
    }
}
int get(int l, int r, int idx, int a){
    while(!tree[idx] && l+1<r){
        int mid = (l+r)/2;
        if(a>=mid) l = mid , idx = idx*2 + 2;
        else r = mid, idx = idx*2 + 1;// a + 1 <= mid
    }
    return tree[idx];
}
int main(){
    int n, l; cin>>n>>l;
    memset(tree, 0, sizeof(tree));
    
    set<int> ss; vector<pair<int, int> > pp;
    for(int i=1; i<=n; i++){
        int a, b; cin>>a>>b;
        ss.insert(a); ss.insert(b);
        pp.push_back(pair<int, int>(a, b));
    }
    map<int, int> mm; int i = 0;
    for(set<int>::iterator it = ss.begin(); it!= ss.end(); it++){
        mm[*it] = i++;    
    }
    
    int N = ss.size();
    for(int i=1; i<=n; i++){
        pair<int, int> &p = pp[i-1];
        _set(0, N-1, 0, mm[p.first], mm[p.second], i);
    }
    set<int> res;
    for(int i=0; i < N - 1; i++){//@attention: i<N-1, the last point 
        int j = get(0, N-1, 0, i); // [i, i+1]   
        if(j) res.insert(j);
    }
    cout<<res.size()<<endl;
    return 0;
}

抱歉!评论已关闭.