• 【BZOJ4653】【NOI2016】区间 [线段树]


    区间

    Time Limit: 60 Sec  Memory Limit: 256 MB
    [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 为该区间的左右端点。

    Output

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

    Sample Input

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

    Sample Output

      2

    HINT

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

    Main idea

      给定若干个区间,取出m个若这m个包含同一个位置则可以统计值,值为这m个中的最大区间长度减去最小区间长度,输出最小值。

    Solution

      发现答案为最大区间长度减去最小区间长度,显然可以先按照长度排序,然后枚举左端点(即最小区间长度),中间小于最大区间长度的区间的加入 只会使得更可能满足条件 而不会影响答案,所以我们用r表示当前加入到了右端点r这个位置,r显然递增,则可以用r一直往后推到满足条件了更新答案,用线段树维护区间+1。因为l[i]与r[i]长度较大,但是发现非常长的长度是不会影响是否可以统计的(因为满足统计的条件只要符合个数>=m即可),所以我们可以对l和r离散化。

    Code

      1 #include<iostream>  
      2 #include<algorithm>  
      3 #include<cstdio>  
      4 #include<cstring>  
      5 #include<cstdlib>  
      6 #include<cmath>  
      7 using namespace std;  
      8     
      9 const int ONE=1000001;
     10 const int INF=2147483640;
     11 
     12 int n,m;
     13 int Ans,res;
     14 int num,cnt;
     15 
     16 struct lisan
     17 {
     18         int pos;
     19         int value;
     20 }Q[ONE*2];
     21 
     22 struct point
     23 {
     24         int l,r;
     25         int value;
     26 }a[ONE];
     27 
     28 struct power
     29 {
     30         int value;
     31         int add;
     32 }Node[ONE*4];
     33 
     34 int cmp(const point &a,const point &b)
     35 {
     36         return a.value<b.value;
     37 }
     38 
     39 int rule(const lisan &a,const lisan &b)
     40 {
     41         return a.value<b.value;
     42 }
     43 
     44 void pushdown(int i)
     45 {
     46         if(Node[i].add)
     47         {
     48             Node[i*2].add+=Node[i].add;
     49             Node[i*2+1].add+=Node[i].add;
     50             Node[i*2].value+=Node[i].add;
     51             Node[i*2+1].value+=Node[i].add;
     52             Node[i].add=0;
     53         }
     54 }
     55 
     56 void Update(int i,int l,int r,int L,int R,int x)
     57 {
     58         if(L<=l && r<=R)
     59         {
     60             Node[i].add+=x;
     61             Node[i].value+=x;
     62             return;
     63         }
     64         pushdown(i);
     65         
     66         int mid=(l+r)/2;
     67         if(L<=mid) Update(i*2,l,mid,L,R,x);
     68         if(mid+1<=R) Update(i*2+1,mid+1,r,L,R,x);    
     69         Node[i].value=max(Node[i*2].value,Node[i*2+1].value);
     70 }
     71 
     72 int get() 
     73 { 
     74         int res,Q=1;    char c;
     75         while( (c=getchar())<48 || c>57)
     76         if(c=='-')Q=-1;
     77         if(Q) res=c-48; 
     78         while((c=getchar())>=48 && c<=57) 
     79         res=res*10+c-48; 
     80         return res*Q; 
     81 }
     82 
     83 void Getlisan()
     84 {
     85         for(int i=1;i<=n;i++)
     86         {
     87             Q[++num].value=a[i].l; Q[num].pos=num;
     88             Q[++num].value=a[i].r; Q[num].pos=num;
     89         }
     90         
     91         sort(Q+1,Q+num+1,rule);
     92         Q[0].value=-1;
     93         for(int i=1;i<=num;i++)
     94         {
     95             if(Q[i].value!=Q[i-1].value) cnt++;
     96             int x=(Q[i].pos+1)/2;
     97             if(Q[i].pos % 2) a[x].l=cnt;
     98             else a[x].r=cnt;
     99         }
    100         
    101         sort(a+1,a+n+1,cmp);
    102 } 
    103 
    104 int main()
    105 {      
    106         n=get();    m=get();
    107         for(int i=1;i<=n;i++)
    108         {
    109             a[i].l=get();    a[i].r=get();
    110             a[i].l++;    a[i].r++; 
    111             a[i].value=a[i].r-a[i].l;
    112         }
    113         Getlisan();
    114         
    115         int r=0;
    116         Ans=INF;
    117         for(int i=1;i<=n;i++)
    118         {
    119             for(;;)
    120             {
    121                 if(Node[1].value>=m || (r+1)>n) break;
    122                 r++;
    123                 Update(1,1,cnt,a[r].l,a[r].r,1);
    124             }
    125             if(Node[1].value>=m)
    126             Ans=min(Ans,a[r].value-a[i].value);
    127             
    128             Update(1,1,cnt,a[i].l,a[i].r,-1);
    129         }
    130         
    131         if(Ans==INF) printf("-1");
    132         else printf("%d",Ans);
    133 }
    View Code
  • 相关阅读:
    在PHP中截取字符串
    SQL查看一张表中是否存在记录
    最多两位小数,如123.45的转换结果为:壹百贰拾叁元肆角伍分
    SQL将金额转换为汉子
    SQL 汉字转换成拼音首字母 首字母查
    SQL生成随机数
    Linux gsoap2.6 webservices
    cxGrid的一些使用方法
    不修改forms.pas单元就可以去掉MDI窗口的滚动条
    今天,我种下了一朵小蓝花
  • 原文地址:https://www.cnblogs.com/BearChild/p/6429858.html
Copyright © 2020-2023  润新知