【NOI2016】区间 题解

题目大意:

  有n个区间,当有m个区间有公共部分时,求m个区间长度的最大值与最小值之差的最小值。

思路:

  按区间的长度从小到大排序,可知连续的几个区间最优,则用两个指针指其头尾,线性扫描,再用线段树区间覆盖。

代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #define N 1000009
 5 #define INF 2147483647
 6 using namespace std;
 7
 8 int n,m,i,j,cnt,ans=INF,sum[N<<2],lazy[N<<2],b[N<<1];
 9 struct node{ int l,r,len; } a[N];
10
11 bool cmp(const node &x,const node &y)
12 {
13     return x.len<y.len;
14 }
15
16 int find(int l,int r,int x)
17 {
18     if (l==r) return l;
19     int mid=l+r>>1;
20     if (x<=b[mid]) find(l,mid,x);
21     else find(mid+1,r,x);
22 }
23
24 void up_date(int k,int x)
25 {
26     sum[k]+=x,lazy[k]+=x;
27 }
28
29 void change(int cur,int L,int R,int l,int r,int val)
30 {
31     if (L==l && R==r) { up_date(cur,val); return; }
32     int mid=L+R>>1;
33     if (lazy[cur])
34     {
35         up_date(cur<<1,lazy[cur]);
36         up_date(cur<<1|1,lazy[cur]);
37         lazy[cur]=0;
38     }
39     if (r<=mid) change(cur<<1,L,mid,l,r,val);
40     else if (l>mid) change(cur<<1|1,mid+1,R,l,r,val);
41          else change(cur<<1,L,mid,l,mid,val),change(cur<<1|1,mid+1,R,mid+1,r,val);
42     sum[cur]=max(sum[cur<<1],sum[cur<<1|1]);
43 }
44
45 void solve()
46 {
47     for (i=1;i<=n;i++)
48     {
49         while (sum[1]<m)
50         {
51             if (j==n) return; j++;
52             change(1,1,cnt,a[j].l,a[j].r,1);
53         }
54         ans=min(ans,a[j].len-a[i].len);
55         change(1,1,cnt,a[i].l,a[i].r,-1);
56     }
57 }
58
59 int main()
60 {
61     scanf("%d%d",&n,&m);
62     for (i=1;i<=n;i++)
63     {
64         scanf("%d%d",&a[i].l,&a[i].r);
65         b[++cnt]=a[i].l,b[++cnt]=a[i].r;
66         a[i].len=a[i].r-a[i].l;
67     }
68     sort(a+1,a+n+1,cmp),sort(b+1,b+cnt+1);
69     for (i=1;i<=n;i++) a[i].l=find(1,cnt,a[i].l),a[i].r=find(1,cnt,a[i].r);
70     solve(); printf("%d\n",ans<INF?ans:-1);
71     return 0;
72 }
时间: 2024-08-06 09:39:48

【NOI2016】区间 题解的相关文章

【BZOJ4653】[Noi2016]区间 双指针法+线段树

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

[Noi2016]区间[离散化+线段树维护+决策单调性]

4653: [Noi2016]区间 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 621  Solved: 329[Submit][Status][Discuss] Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就是使得存在一个 x,使得对于每一个被选中的区间 [li,ri],都有 li≤x≤ri. 对于一个合法的

[Noi2016]区间

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

bzoj 4653: [Noi2016]区间

额,是不是一到了晚上IQ就--: 这个题一开始完全没有思路.(貌似脑子就没动一下) %了一下题解. 大概是决策是有单调性的,因为要去区间长度差最小,所以接排个序,然后扫描右端点,找出满足有点被覆盖m次的最右的左端点就好. 然后判断是不是有覆盖m个点的用线段树维护一下. (23333,吐槽,为什么离散化二分的时候,把左端点搞成0,右端点搞成L就会RE??excuse me?!!) 1 #include<bits/stdc++.h> 2 #define LL long long 3 #define

[BZOJ4653][Noi2016]区间

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

【uoj222】 NOI2016—区间

http://uoj.ac/problem/222 (题目链接) 题意:有n个区间,当有m个区间有公共部分时,求m个区间长度的最大值与最小值之差的最小值. Solution  线段树+滑动窗口.这道题很好做,可是在考场上就差一点点,我愣是没想出来.  先将区间按长度排序,保证它们的长度是递增的,这样就可以滑动窗口了.将区间的端点离散化后,用线段树维护每个节点被覆盖的次数,记录当前区间被覆盖次数最多的点被覆盖多少次,当次数达到要求是更新答案,将头指针向后移动. 代码: // uoj222 #inc

UOJ222 NOI2016 区间 线段树+FIFO队列

首先将区间按长度排序后离散化端点(这里的“长度”指的是离散化之前区间的实际长度) 然后模拟一个队列,区间按排好的顺序依次进入,直到某个点被覆盖了M次.之后依次出队,直到所有点都被覆盖小于M次 修改和询问覆盖次数可以用线段树实现 1 //C++11 code 2 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 7 const int maxN=500005; 8 const int inf

BZOJ3226[Sdoi2008]校门外的区间 题解

题目大意: 有5种运算维护集合S(S初始为空)并最终输出S. 5种运算如下: U T S∪T I T S∩T D T S-T C T T-S S T S⊕T 基本集合运算如下: A∪B      {x : xÎA or xÎB} A∩B      {x : xÎA and xÎB} A-B      {x : xÎA and xÏB} A⊕B      (A-B)∪(B-A) 思路: 每个数之间加入一个数,就像这样2 2.5 3 3.5 4 [2,3) -> [2,2.5] (3,4] ->

[UOJ #222][NOI2016]区间(线段树)

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