BZOJ_4653_[Noi2016]区间_线段树+离散化+双指针

Description

在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn]。现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置。换句话说,就是使得存在一个 x,使得对于每一个被选中的区间 [li,ri],都有 li≤x≤ri。

对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。区间 [li,ri] 的长度定义为 ri−li,即等于它的右端点的值减去左端点的值。

求所有合法方案中最小的花费。如果不存在合法的方案,输出 −1。

Input

第一行包含两个正整数 n,m用空格隔开,意义如上文所述。保证 1≤m≤n

接下来 n行,每行表示一个区间,包含用空格隔开的两个整数 li 和 ri 为该区间的左右端点。

N<=500000,M<=200000,0≤li≤ri≤10^9

Output

只有一行,包含一个正整数,即最小花费。

Sample Input

6 3
3 5
1 2
3 4
2 2
1 5
1 4

Sample Output

2


把区间按长度排序。

可以发现我选择一段连续区间的区间一定不会使答案变差。并且合法的两个端点单调。

于是可以用双指针扫一遍,每次确定合法的最短的区间,更新答案。

每次加入/删除一个区间相当于区间加/减,区间求最值操作,这个可以用线段树实现。

区间需要离散化,有用的只有左右端点。

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 500050
#define ls p<<1
#define rs p<<1|1
int n,m,turn[N<<1],maxn;
int t[N<<3],add[N<<3];
struct A {
    int l,r,lx,rx;
}q[N];
bool cmp1(const A &x,const A &y) {return x.r-x.l<y.r-y.l;}
int p[N<<1];
inline void pushup(int p) {
    t[p]=max(t[ls],t[rs]);
}
inline void pushdown(int p) {
    int d;
    if(d=add[p]) {
        t[ls]+=d; t[rs]+=d;
        add[ls]+=d; add[rs]+=d;
        add[p]=0;
    }
}
void update(int l,int r,int x,int y,int v,int p) {
    if(x<=l&&y>=r) {
        t[p]+=v; add[p]+=v;
        return ;
    }
    pushdown(p);
    int mid=(l+r)>>1;
    if(x<=mid) update(l,mid,x,y,v,ls);
    if(y>mid) update(mid+1,r,x,y,v,rs);
    pushup(p);
}
int query(int l,int r,int x,int y,int p) {
    if(x<=l&&y>=r) return t[p];
    pushdown(p);
    int mid=(l+r)>>1,re=0;
    if(x<=mid) re=max(re,query(l,mid,x,y,ls));
    if(y<mid) re=max(re,query(mid+1,r,x,y,rs));
    pushup(p);
    return re;
}
int main() {
    scanf("%d%d",&n,&m);
    int i,x,y;
    for(i=1;i<=n;i++) {
        scanf("%d%d",&q[i].l,&q[i].r);
        p[i]=q[i].l,p[i+n]=q[i].r;
    }
    sort(p+1,p+2*n+1);
    int j=0;p[0]=5343453;
    for(i=1;i<=n;i++) {
        q[i].lx=lower_bound(p+1,p+n+n+1,q[i].l)-p;
        q[i].rx=lower_bound(p+1,p+n+n+1,q[i].r)-p;
    }
    maxn=2*n;
    sort(q+1,q+n+1,cmp1);
    //for(i=1;i<=n;i++) printf("%d %d\n",turn[q[i].l],turn[q[i].r]);
    int l=1,r=0,ans=1<<30;
    while(r<n) {
        while(t[1]<m&&r<n) r++,update(1,maxn,q[r].lx,q[r].rx,1,1);
        if(t[1]<m) break;
        while(t[1]>=m&&l<n) update(1,maxn,q[l].lx,q[l].rx,-1,1),l++;
        ans=min(ans,q[r].r-q[r].l-q[l-1].r+q[l-1].l);
    }
    printf("%d\n",ans<(1<<30)?ans:-1);
}

原文地址:https://www.cnblogs.com/suika/p/8997997.html

时间: 2024-10-09 22:57:39

BZOJ_4653_[Noi2016]区间_线段树+离散化+双指针的相关文章

[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

poj 2528 Mayor&#39;s posters(线段树 离散化 区间更新 贴海报)

     这个题目本来对大神来说可能是水题, 对我就不行了,昨晚非折腾到下半夜一点 搞定, 并且可以总结出 ,只有把问题想清楚,或着看人家解题报告自己把问题和代码思路 搞清楚,才能谈的上调bug,否则根本就不知道错在哪儿.说说这个题目的理解,他是如何转化为线段树问题的呢?我们知道线段树有一个区间更新的东西,每张海报的宽度不就是一个区间么?那么我们可以用一棵树中的部分结点 来表示整张海报的可视部分,也就是说每个结点只允许表示一张完整的或着不完整的海报(好几个结点才可以表示成完整的一张海报),那么如

POJ_2528 Mayor&#39;s poster(线段树+离散化)

题目请点我 题解: 这道题与之前的题目相比重点在于一个映射的预处理,题目所给的区间达到10000000,而最多只有10000个点,如果直接建树的话太过于空旷.把这些区间的左右节点一一对应,最多有4×10000个点,远小于之前的10000000,而且区间之间的对应关系也不会改变. 举个例子: 区间:[2,6],[4,8],[6,10] 我们进行下面对应: 2 4 6 8 10 1 2 3 4 5 则原区间变为[1,3],[2,4],[3,5].可以发现它们之间的覆盖关系并没有改变,但是却紧凑了很多

HDU5124:lines(线段树+离散化)或(离散化思想)

http://acm.hdu.edu.cn/showproblem.php?pid=5124 Problem Description John has several lines. The lines are covered on the X axis. Let A is a point which is covered by the most lines. John wants to know how many lines cover A. Input The first line conta

Poj 2528 Mayor&#39;s posters (线段树+离散化)

题目连接: http://poj.org/problem?id=2528 题目大意: 有10000000块瓷砖,n张海报需要贴在墙上,每张海报所占的宽度和瓷砖宽度一样,长度是瓷砖长度的整数倍,问按照所给海报顺序向瓷砖上贴海报,最后有几张海报是可见的? 解题思路: 因为瓷砖块数和海报张数多,首选线段树,如果按照常规的建树方式,把瓷砖当做数的节点,肯定会MTL......... 所以我们可以用海报的起点和终点当做树的节点,这样树的节点才有20000个,但是这样建树的话,求海报覆盖了那些节点会很复杂,

hdu 5124 lines (线段树+离散化)

lines Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 620    Accepted Submission(s): 288 Problem Description John has several lines. The lines are covered on the X axis. Let A is a point which

POJ 2528 (线段树+离散化) Mayor&#39;s posters

因为将每个单位都作为一个最小单元的话会爆内存的 所以,将海报的每个端点进行排序,将这些端点最为最小的区间. 毕竟是刚刚接触线段树,理解起来还有些吃力,还是那句话,题做多了慢慢就好了. 萌萌的AC代码君贴上. 1 //#define LOCAL 2 #include <iostream> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 7 int n; 8 struct CPost 9

poj2528--Mayor&#39;s posters(线段树+离散化)

Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 41785   Accepted: 12164 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral post

【线段树+离散化】POJ2528 Mayor&#39;s posters

Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 64939   Accepted: 18770 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral post