bzoj 4653: [Noi2016]区间

额,是不是一到了晚上IQ就--;

这个题一开始完全没有思路。(貌似脑子就没动一下)

%了一下题解。

大概是决策是有单调性的,因为要去区间长度差最小,所以接排个序,然后扫描右端点,找出满足有点被覆盖m次的最右的左端点就好。

然后判断是不是有覆盖m个点的用线段树维护一下。

(23333,吐槽,为什么离散化二分的时候,把左端点搞成0,右端点搞成L就会RE??excuse me?!!)

 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 #define inf 0x7fffffff
 4 using namespace std;
 5 inline int ra()
 6 {
 7     int x=0,f=1; char ch=getchar();
 8     while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();}
 9     while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();}
10     return x*f;
11 }
12
13 const int maxn=500005;
14
15 struct seg{int l,r,tag,mx;}t[maxn<<3];
16 struct data{int x,y,len;}a[maxn];
17
18 int L,n,m,b[maxn<<1],tot,ans=inf;
19 bool cmp_len(data a, data b){return a.len<b.len;}
20 int find(int x)
21 {
22     int l=1,r=L-1;
23     while (l<=r)
24     {
25         int mid=l+r>>1;
26         if (b[mid]==x) return mid;
27         else if (b[mid]<x) l=mid+1;
28         else r=mid-1;
29     }
30 }
31 void build(int k, int l, int r)
32 {
33     t[k].l=l; t[k].r=r;
34     if (l==r) return;
35     int mid=l+r>>1;
36     build(k<<1,l,mid); build(k<<1|1,mid+1,r);
37 }
38 void pushdown(int k)
39 {
40     int tmp=t[k].tag; t[k].tag=0;
41     t[k<<1].tag+=tmp; t[k<<1|1].tag+=tmp;
42     t[k<<1].mx+=tmp; t[k<<1|1].mx+=tmp;
43 }
44 void update(int k) {t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx);}
45 void change(int k, int x, int y, int val)
46 {
47     int l=t[k].l,r=t[k].r;
48     if (x==l && y==r)
49     {
50         t[k].tag+=val; t[k].mx+=val;
51         return;
52     }
53     if (t[k].tag) pushdown(k);
54     int mid=l+r>>1;
55     if (y<=mid) change(k<<1,x,y,val);
56     else if (x>mid) change(k<<1|1,x,y,val);
57     else change(k<<1,x,mid,val),change(k<<1|1,mid+1,y,val);
58     update(k);
59 }
60 int main()
61 {
62 //    freopen("bzoj4653_data.in","r",stdin);
63 //    freopen("bzoj4653_data.out","w",stdout);
64     n=ra(); m=ra();
65     if (!m) {puts("0");return 0;}
66     for (int i=1; i<=n; i++)
67     {
68         a[i].x=ra(),a[i].y=ra(),a[i].len=a[i].y-a[i].x;
69         b[++tot]=a[i].x; b[++tot]=a[i].y;
70     }
71     sort(a+1,a+n+1,cmp_len); sort(b+1,b+tot+1);
72     L=unique(b+1,b+tot+1)-b;
73     for (int i=1; i<=n; i++) a[i].x=find(a[i].x),a[i].y=find(a[i].y);
74     int now=1; build(1,1,L);
75     for (int i=1; i<=n; i++)
76     {
77         change(1,a[i].x,a[i].y,1);
78         while (t[1].mx>=m)
79         {
80             ans=min(ans,a[i].len-a[now].len);
81             change(1,a[now].x,a[now].y,-1);
82             now++;
83         }
84     }
85     printf("%d\n",ans==inf?-1:ans);
86     return 0;
87 }
时间: 2024-10-13 16:33:29

bzoj 4653: [Noi2016]区间的相关文章

[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. 对于一个合法的

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

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

AC日记——NOI2016区间 bzoj 4653

4653 思路: 线段树,指针滑动: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1000005 #define maxm 200005 #define maxn_ maxn<<2 #define INF 0x7fffffff struct TreeNodeType { int l,r,dis,mid,flag; }; struct TreeNodeType tree[maxn_]; struct Q

区间(bzoj 4653)

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

[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

[BZOJ4653][Noi2016]区间

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

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

[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