区间求差

本体来自 hihocoder #1305

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

给定两个区间集合 A 和 B,其中集合 A 包含 N 个区间[ A1A2 ], [ A3A4 ], ..., [ A2N-1A2N ],集合 B 包含 M 个区间[ B1B2 ], [ B3B4 ], ..., [ B2M-1B2M ]。求 A - B 的长度。

例如对于 A = {[2, 5], [4, 10], [14, 18]}, B = {[1, 3], [8, 15]}, A - B = {(3, 8), (15, 18]},长度为8。

输入

第一行:包含两个整数 N 和 M (1 ≤ NM ≤ 100000)。

第二行:包含 2N 个整数 A1A2, ..., A2N (1 ≤ Ai ≤ 100000000)。

第三行:包含 2M 个整数 B1B2, ..., B2M (1 ≤= Bi ≤ 100000000)。

输出

一个整数,代表 A - B 的长度。

样例输入

3 2
2 5 4 10 14 18
1 3 8 15

样例输出

8

分析

这道题的思路并不复杂,很容易想到,我们可以先对A、B中的区间进行合并,得到一些彼此不交的区间,这些区间按位置排序,然后对于A中每个区间,考察所有覆盖住该区间的B中区间,则该区间对A-B的贡献就是这些B中区间之间的缝隙。显然,这样做我们得到的算法的复杂度是O(NlogN)。

代码如下:

#include<iostream>
#include<vector>
#include<deque>
#include<stack>
#include<string>
#include<algorithm>
#include<string.h>
#include<sstream>

using namespace std;

struct Interval {
    int start;
    int end;
    Interval() :start(0), end(0) {}
    Interval(int a, int b) :start(a), end(b) {}
};

const int max_n = 100000;
Interval a[max_n];
Interval b[max_n];

bool in_cmp(const Interval& a, const Interval& b){
    return a.start < b.start;
}

bool is_overlap(Interval& a, Interval& b){
    if (a.end < b.start) return false;
    if (b.end < a.start) return false;

    return true;
}

Interval my_union(Interval& a, Interval& b){
    int start = min(a.start, b.start);
    int end = max(a.end, b.end);

    Interval u(start, end);
    return u;
}

void union_in(int N, int M, vector<Interval>& a_u, vector<Interval>& b_u) {
    sort(a, a + N, in_cmp);
    int i = 0;
    while (i < N) {
        Interval now_in = a[i];
        int j = i + 1;
        while (j < N){
            if (is_overlap(a[j], now_in)) {
                now_in = my_union(now_in, a[j]);
                ++j;
            }
            else break;
        }
        a_u.push_back(now_in);
        i = j;
    }

    sort(b, b + M, in_cmp);
    i = 0;
    while (i < M) {
        Interval now_in = b[i];
        int j = i + 1;
        while (j < M){
            if (is_overlap(b[j], now_in)) {
                now_in = my_union(now_in, b[j]);
                ++j;
            }
            else break;
        }
        b_u.push_back(now_in);
        i = j;
    }
}

int sol(vector<Interval> &a_u, vector<Interval> &b_u) {
    int res = 0;

    auto it_a = a_u.begin();
    auto it_b = b_u.begin();
    while (it_a != a_u.end()) {
        if (it_b == b_u.end() || (it_b->end >= it_a->start && !is_overlap(*it_b, *it_a))) {
            res += it_a->end - it_a->start;
            ++it_a;
        }
        else if (it_b->end < it_a->start) {
            ++it_b;
        }
        else {
            if (it_b->start > it_a->start) res += it_b->start - it_a->start;

            auto it_be = it_b + 1;
            while (it_be != b_u.end() && is_overlap(*it_be, *it_a)) {
                res += it_be->start - (it_be - 1)->end;
                ++it_be;
            }
            --it_be;
            if (it_be->end < it_a->end) res += it_a->end - it_be->end;
            ++it_a;
            it_b = it_be;
        }
    }

    return res;

}

int main() {

    int N, M;

    cin >> N >> M;
    for (int i = 0; i < N; ++i) {
        int x, y;
        cin >> x >> y;
        a[i].start = x;
        a[i].end = y;
    }
    for (int i = 0; i < M; ++i) {
        int x, y;
        cin >> x >> y;
        b[i].start = x;
        b[i].end = y;
    }

    vector<Interval> a_u;
    vector<Interval> b_u;
    union_in(N, M, a_u, b_u);

    int res = sol(a_u, b_u);

    cout << res << endl;

    //system("pause");

    return 0;
}
时间: 2024-10-21 08:23:35

区间求差的相关文章

hiho #1305 区间求差

#1305 : 区间求差 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定两个区间集合 A 和 B,其中集合 A 包含 N 个区间[ A1, A2 ], [ A3, A4 ], ..., [ A2N-1, A2N ],集合 B 包含 M 个区间[ B1, B2 ], [ B3, B4 ], ..., [ B2M-1, B2M ].求 A - B 的长度. 例如对于 A = {[2, 5], [4, 10], [14, 18]}, B = {[1, 3], [8,

poj3264(线段树区间求最值)

题目连接:http://poj.org/problem?id=3264 题意:给定Q(1<=Q<=200000)个数A1,A2,```,AQ,多次求任一区间Ai-Aj中最大数和最小数的差. 线段树功能:区间求最值,O(logN)复杂度查询 #pragma comment(linker,"/STACK:102400000,102400000") #include <cstdio> #include <cstring> #include <stri

RMQ(区间求最值)

1. 概述 RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j之间的最小/大值.这两个问题是在实际应用中经常遇到的问题,下面介绍一下解决这两种问题的比较高效的算法.当然,该问题也可以用线段树(也叫区间树)解决,算法复杂度为:O(N)~O(logN),这里我们暂不介绍. 2.RMQ算法 对于该问题,最容易想到的解决方案是遍历,复杂度是O(n).但当数据量

hdu4521-小明系列问题——小明序列(线段树区间求最值)

题意:求最长上升序列的长度(LIS),但是要求相邻的两个数距离至少为d,数据范围较大,普通dp肯定TLE.线段树搞之就可以了,或者优化后的nlogn的dp. 代码为  线段树解法. 1 #include <set> 2 #include <map> 3 #include <cmath> 4 #include <ctime> 5 #include <queue> 6 #include <stack> 7 #include <cct

poj 2763 树链剖分(单点更新,区间求值)

http://poj.org/problem?id=2763 Description After their royal wedding, Jiajia and Wind hid away in XX Village, to enjoy their ordinary happy life. People in XX Village lived in beautiful huts. There are some pairs of huts connected by bidirectional ro

区间求最值 线段树

湖南师范大学 11460 区间求最值 区间求最值   Problem description   给定一个长度为N 的数组,有q个询问,每个询问是求在数组的一段区间内那个元素的因子的个数最大,比如24的因子的个数就是8.  Input   首先是一个整数t,表示有t组测试数据,每组测试数据的第一行是一个整数N(1<=N<=10^6),第二行有N个整数ai(1<=ai<=10^6,i=1,2,.....N)表示数组的元素.第三行有一个整数q(1<=q<=10^5),代表有

HDU - 1754 I Hate It (线段树区间求最值)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1754 题意:线段树的单点更新和区间求最值 模板题,,,???,, 1 #include <cstdio> 2 #include <iostream> 3 using namespace std; 4 5 typedef long long LL; 6 const int N=200010; 7 8 LL ans; 9 LL max(LL a,LL b){ 10 if(a>b) r

hdu 1754 I Hate It(树状数组区间求最值)2007省赛集训队练习赛(6)_linle专场

题意: 输入一行数字,查询第i个数到第j个数之间的最大值.可以修改其中的某个数的值. 输入: 包含多组输入数据. 每组输入首行两个整数n,m.表示共有n个数,m次操作. 接下来一行包含n个整数. 接下来m行,每行包含一个字母s,两个整数a,b. 当s为’Q’,表示查询第a个数到第b个数之间的最大值. 当s为’U’,表示将第a个数更改为b. 输出: 每次查询输出一个结果,每次输出占一行. 题解: 点修改区间求最值,可以用树状数组模板. 具体见代码—— 1 #include <cstdio> 2

linux_coom _ Linux文件比较,文本文件的交集、差集与求差

交集和差集操作在集合论相关的数学课上经常用到,不过,在Linux下 对文本进行类似的操作在某些情况下也很有用. comm命令 comm命令可以用于两个文件之间的 比较,它有一些选项可以用来调整输出,以便执行交集.求差.以及差集操作. 交集:打印出两个文件所共有的行. 求差:打印出指定文件所包含的且不相同的行. 差集:打印出包含在一个文件中,但不包含在其他指定文件中的行. [[email protected] text]# cat aaa.txt aaabbbcccdddeee111222 [[e