Luogu_2434_[SDOI2005]区间

题目描述

现给定n个闭区间[ai, bi],1<=i<=n。这些区间的并可以表示为一些不相交的闭区间的并。你的任务就是在这些表示方式中找出包含最少区间的方案。你的输出应该按照区间的升序排列。这里如果说两个区间[a, b]和[c, d]是按照升序排列的,那么我们有a<=b<c<=d。

请写一个程序:

读入这些区间;

计算满足给定条件的不相交闭区间;

把这些区间按照升序输出。

输入输出格式

输入格式

第一行包含一个整数n,3<=n<=50000,为区间的数目。以下n行为对区间的描述,第i行为对第i个区间的描述,为两个整数1<=ai<bi<=1000000,表示一个区间[ai, bi]。

输出格式

输出计算出来的不相交的区间。每一行都是对一个区间的描述,包括两个用空格分开的整数,为区间的上下界。你应该把区间按照升序排序。

样例

INPUT

5

5 6

1 4

10 10

6 9

8 10

OUTPUT

1 4

5 10

HINT

SOLUTION

差分

接下来有10行废话。

这题不难。

我想过贪心,想过区间dp,想过建树bfs,就是没想到差分。

先看数据范围:\(3\leq n \leq 50000,1\leq a_i<b_i\leq 1000000\),

首先我们就把\(O(n^2)\)的方案给毙掉了。

这种题不是\(O(n)\)就是\(O(nlogn)\),对吧。

建树不好建,建了也不知道怎么写,毙掉。

就剩\(O(n)\)的了。

dp?怎么写啊?我不会,毙掉。

贪心把区间从头开始往后拓,直到出现断点?那万一全部连起来了呢?不好找断点,毙掉。

然后把目光放在这里:\(1\leq a_i<b_i\leq 1000000\),说不定有\(O(max(b_i))\)的写法呢?然后老老实实翻了题解。。。

所以我们考虑差分。

进来一个左端点就在相应位置+1,进来一个右端点就在相应位置-1,对,这就是典型的差分。

当我们的点的左边为正,而当前点为0,这说明有若干(也可能只有一)对区间从这里开始。

同理,当我们的点的右边为0,而当前点为0,这说明有若干(也可能只有一)对区间在这里完成了匹配,可以断开作为一段完整区间。

然后注意一下形同\([i,i]\)的区间要特判一下就可以了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define Min(a,b) ((a<b)?a:b)
#define Max(a,b) ((a>b)?a:b)
const int N=101000,M=1010000;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while (ch<‘0‘||ch>‘9‘) {if (ch==‘-‘) f=-1;ch=getchar();}
    while (ch>=‘0‘&&ch<=‘9‘) {x=x*10+ch-48;ch=getchar();}
    return x*f;}
struct NODE{int d,u;}nd[N];
bool cmp(NODE a,NODE b) {return a.d<b.d;}
struct ITV{int l,r;}ans[N];
int n,itv[M],L=M,R=0;
int main(){
    int i,j;
    n=read();int cnt=0;
    for (i=1;i<=n;++i){
        nd[++cnt].d=read();nd[cnt].u=1;L=Min(L,nd[cnt].d);R=Max(R,nd[cnt].d);
        nd[++cnt].d=read();nd[cnt].u=-1;L=Min(L,nd[cnt].d);R=Max(R,nd[cnt].d);}
    memset(itv,0,sizeof(itv));
    sort(nd+1,nd+1+cnt,cmp);
    int p=1;cnt=0;
    for (i=L;i<=R;++i){
        itv[i]=itv[i-1];int flg=0,rec=0;
        while ((nd[p].d==i)&&(p<=2*n)) {flg=1;rec+=nd[p].u;itv[i]+=nd[p].u;p++;}
        if ((!itv[i-1])&&(flg)&&(!rec)) {ans[++cnt].l=i;ans[cnt].r=i;}//对于[i,i]型区间的特判
        if ((!(itv[i-1]))&&(itv[i])) ans[++cnt].l=i;
            else if ((itv[i-1])&&(!(itv[i]))) ans[cnt].r=i;
    }
    for (i=1;i<=cnt;++i) printf("%d %d\n",ans[i].l,ans[i].r);
    return 0;
}

原文地址:https://www.cnblogs.com/hkpls/p/9812199.html

时间: 2024-10-14 23:43:48

Luogu_2434_[SDOI2005]区间的相关文章

P2434 [SDOI2005]区间

P2434 [SDOI2005]区间 题目描述 现给定n个闭区间[ai, bi],1<=i<=n.这些区间的并可以表示为一些不相交的闭区间的并.你的任务就是在这些表示方式中找出包含最少区间的方案.你的输出应该按照区间的升序排列.这里如果说两个区间[a, b]和[c, d]是按照升序排列的,那么我们有a<=b<c<=d. 请写一个程序: 读入这些区间: 计算满足给定条件的不相交闭区间: 把这些区间按照升序输出. 输入输出格式 输入格式: 第一行包含一个整数n,3<=n&l

洛谷——P2434 [SDOI2005]区间

P2434 [SDOI2005]区间 题目描述 现给定n个闭区间[ai, bi],1<=i<=n.这些区间的并可以表示为一些不相交的闭区间的并.你的任务就是在这些表示方式中找出包含最少区间的方案.你的输出应该按照区间的升序排列.这里如果说两个区间[a, b]和[c, d]是按照升序排列的,那么我们有a<=b<c<=d. 请写一个程序: 读入这些区间: 计算满足给定条件的不相交闭区间: 把这些区间按照升序输出. 输入输出格式 输入格式: 第一行包含一个整数n,3<=n&l

[SDOI2005]区间

题目描述 现给定n个闭区间[ai, bi],1<=i<=n.这些区间的并可以表示为一些不相交的闭区间的并.你的任务就是在这些表示方式中找出包含最少区间的方案.你的输出应该按照区间的升序排列.这里如果说两个区间[a, b]和[c, d]是按照升序排列的,那么我们有a<=b<c<=d. 请写一个程序: 读入这些区间: 计算满足给定条件的不相交闭区间: 把这些区间按照升序输出. 输入输出格式 输入格式: 第一行包含一个整数n,3<=n<=50000,为区间的数目.以下n

「SDOI2005」区间

「SDOI2005」区间 传送门 记录每一个位置作为左端点和右端点的出现次数,然后直接考虑差分即可. 参考代码: #include <cstdio> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout) template < class T > inline void

饥饿的牛 线性dp内的区间

饥饿的牛 牛在饲料槽前排好了队.饲料槽依次用1到N(1<=N<=100000)编号.每天晚上,一头幸运的牛根据约翰的规则,吃其中一些槽里的饲料. 约翰提供B个区间的清单.一个区间是一对整数start-end,1<=start<=end<=N,表示一些连续的饲料槽,比如1-3,7-8,3-4等等.牛可以任意选择区间,但是牛选择的区间不能有重叠.当然,牛希望自己能够吃得越多越好.给出一些区间,帮助这只牛找一些区间,使它能吃到最多的东西.在上面的例子中,1-3和3-4是重叠的:聪明

POJ - 3186 Treats for the Cows (区间DP)

题目链接:http://poj.org/problem?id=3186 题意:给定一组序列,取n次,每次可以取序列最前面的数或最后面的数,第n次出来就乘n,然后求和的最大值. 题解:用dp[i][j]表示i~j区间和的最大值,然后根据这个状态可以从删前和删后转移过来,推出状态转移方程: dp[i][j]=max(dp[i+1][j]+value[i]*k,dp[i][j-1]+value[j]*k) 1 #include <iostream> 2 #include <algorithm&

[Noi2016]区间

题目描述 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就是使得存在一个 x,使得对于每一个被选中的区间 [li,ri],都有 li≤x≤ri. 对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度.区间 [li,ri] 的长度定义为 ri?li,即等于它的右端点的值减去左端点的值. 求所有合法方案中最小的花费.如果不存在合法的方案,输出 ?1. 输入输出格式

7620:区间合并

7620:区间合并 总时间限制: 1000ms 内存限制: 65536kB 描述 给定 n 个闭区间 [ai; bi],其中i=1,2,...,n.任意两个相邻或相交的闭区间可以合并为一个闭区间.例如,[1;2] 和 [2;3] 可以合并为 [1;3],[1;3] 和 [2;4] 可以合并为 [1;4],但是[1;2] 和 [3;4] 不可以合并. 我们的任务是判断这些区间是否可以最终合并为一个闭区间,如果可以,将这个闭区间输出,否则输出no. 输入 第一行为一个整数n,3 ≤ n ≤ 5000

luogu 1712 区间(线段树+尺取法)

题意:给出n个区间,求选择一些区间,使得一个点被覆盖的次数超过m次,最小的花费.花费指的是选择的区间中最大长度减去最小长度. 坐标值这么大,n比较小,显然需要离散化,需要一个技巧,把区间转化为半开半闭区间,然后线段树的每一个节点表示一个半开半闭区间. 接着我们注意到需要求最小的花费,且这个花费只与选择的区间集合中的最大长度和最小长度有关. 这意味着如果最大长度和最小长度一定,我们显然是需要把中间长度的区间尽量的选择进去使答案不会变的更劣. 不妨把区间按长度排序,枚举每个最小长度区间,然后最大区间