zoukankan      html  css  js  c++  java
  • 【BZOJ-4653】区间 线段树 + 排序 + 离散化

    4653: [Noi2016]区间

    Time Limit: 60 Sec  Memory Limit: 256 MB
    Submit: 107  Solved: 70
    [Submit][Status][Discuss]

    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

    HINT

    Source

    Solution

    比较简单的题

    显然先对区间左右端点进行离散化

    考虑按区间长度排序,用双指针统计答案

    排序后,由于单调性,答案显然是两段连续的区间,那么扫一遍区间,判断多个区间是否有交M即可

    用数据结构去维护多个区间求交,显然线段树即可

    基本的操作:区间修改,总体查询最大

    然后每次到达M更新答案即可

    Code

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    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-'0'; ch=getchar();}
        return x*f;
    }
    #define MAXN 500100
    int N,M,ls[MAXN<<2],tp,top;
    struct QNode{int l,r,sz;}q[MAXN<<2];
    struct SegmentTreeNode{int l,r,tag,maxx;}tree[MAXN<<4];
    inline void Update(int now) {tree[now].maxx=max(tree[now<<1].maxx,tree[now<<1|1].maxx);}
    void Pushdown(int now)
    {
        if (!tree[now].tag) return;
        int D=tree[now].tag; tree[now].tag=0;
        tree[now<<1].maxx+=D; tree[now<<1|1].maxx+=D;
        tree[now<<1].tag+=D; tree[now<<1|1].tag+=D;
    }
    void Change(int now,int l,int r,int L,int R,int D)
    {
        if (L<=l && R>=r) {tree[now].tag+=D; tree[now].maxx+=D; return;}
        Pushdown(now);
        int mid=(l+r)>>1;
        if (L<=mid) Change(now<<1,l,mid,L,R,D);
        if (R>mid) Change(now<<1|1,mid+1,r,L,R,D);
        Update(now);
    }
    bool cmp(QNode A,QNode B) {return A.sz<B.sz;}
    int Solve()
    {
        int re=0x7fffffff,dfn=0;
        sort(q+1,q+N+1,cmp);
        for (int i=1; i<=N; i++)
            {
                while (tree[1].maxx<M)
                    {
                        if (dfn==N) return re;
                        dfn++;
                        Change(1,1,top,q[dfn].l,q[dfn].r,1);
                    }
                re=min(q[dfn].sz-q[i].sz,re);
                Change(1,1,top,q[i].l,q[i].r,-1);
            }
        return re;
    }
    int main()
    {
        N=read(),M=read();
        for (int i=1; i<=N; i++)
            ls[++tp]=q[i].l=read(),ls[++tp]=q[i].r=read(),q[i].sz=q[i].r-q[i].l;
        sort(ls+1,ls+tp+1);
        ls[top]=-1;
        for (int i=1; i<=tp; i++) if (ls[i]!=ls[top]) ls[++top]=ls[i];
        for (int i=1; i<=N; i++)
            q[i].l=lower_bound(ls+1,ls+top+1,q[i].l)-ls,q[i].r=lower_bound(ls+1,ls+top+1,q[i].r)-ls;
        int Ans=Solve();
        printf("%d
    ",Ans==0x7fffffff? -1:Ans);
        return 0;
    } 

    由于同步赛的时候就想到了正解,并且打了一遍,放学前花10分钟又码了一遍...

    一开始线段树写了个建树...最后几个点RE成狗.....然后回到最初辣鸡版本,把建树扔了就轻松A了....

    被DCrusher大爷嘲讽了一顿

    同步赛好像也是这么写的,应该能A?

  • 相关阅读:
    自定义事件的触发dispatchEvent
    [转]ProxmoxVE 干掉 VMware
    【转】怎么去阅读Chromium的源码?
    Delphi内存专题
    Delphi 线程同步技术(转)
    【纸模】六角大王 Super 5.6 CHS 简体中文版 U20080725+[手册]窗口与工具的概要(PDF格式)
    ReSharper反编译C#类库
    CS DevExpress程序启动(主窗体初始化优化)
    【EasyNetQ】- 发布/订阅模式
    Intellij Idea调试java文件时 怎么跳过class文件?
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5743254.html
Copyright © 2011-2022 走看看