zoukankan      html  css  js  c++  java
  • BZOJ4653 [NOI2016] 区间 【线段树】

    题目分析:

    首先思考一个二分答案的做法。我们可以注意到答案具有单调性,所以可以二分答案。

    假设当前二分的答案是$ k $。那么按照大小顺序插入每个区间,同时在末端删除会对答案产生影响的区间。这里不妨用线段树维护。这个做法在外国好像叫做two pointers。

    如果某个时刻,线段树中有点大于等于$ m $,说明这个答案是合理的,可以向上二分。若全程没有点大于$ m $说明这个答案不合理,向下二分。

    时间复杂度是$ O(nlognlogN) $的,会超时。

    从这个方法入手,考虑如何优化。实际上,二分是不必要的。同样我们可以采用two pointers。如果某个时刻线段树中有点等于$ m $。我们完全可以从后端删除点。这是为什么呢?

    理由是从后端删除掉的点与其它点产生的共鸣(姑且这么叫吧)肯定比当前的答案要大,若以删除对更好的答案是没有影响的。这样我们可以删除直到线段树中没有点等于$ m $。同时记录答案。

    时间复杂度是$ O(nlogn) $的,可以通过所有数据。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn = 520000;
     5     
     6 int n,m,Num;
     7 
     8 int mp[maxn<<1];
     9 
    10 struct Dir{
    11     int l,r,len;
    12 }d[maxn];
    13 
    14 class SegmentTree{
    15 private:
    16     int lazy[maxn<<3],maxx[maxn<<3];
    17     void push_down(int now){
    18     maxx[now<<1] += lazy[now]; lazy[now<<1] += lazy[now];
    19     maxx[now<<1|1] += lazy[now]; lazy[now<<1|1] += lazy[now];
    20     lazy[now] = 0;
    21     }
    22     void push_up(int now){maxx[now] = max(maxx[now<<1],maxx[now<<1|1]);}
    23 public:
    24     void add(int now,int l,int r,int tl,int tr,int val){
    25     if(lazy[now] && tl != tr) push_down(now);
    26     if(tl >= l && tr <= r){
    27         lazy[now] +=val; maxx[now]+=val;
    28         return;
    29     }
    30     if(tl > r || tr < l) return;
    31     int mid = (tl+tr)/2;
    32     add(now<<1,l,r,tl,mid,val);
    33     add(now<<1|1,l,r,mid+1,tr,val);
    34     push_up(now);
    35     }
    36     int Query(){return maxx[1];}
    37 }T;
    38 
    39 int cmp(Dir a,Dir b){
    40     if(a.len<b.len) return true;
    41     else return false;
    42 }
    43 
    44 void read(){
    45     scanf("%d%d",&n,&m);
    46     for(int i=1;i<=n;i++){
    47     scanf("%d%d",&d[i].l,&d[i].r); d[i].len = d[i].r-d[i].l;
    48     mp[++Num] = d[i].l; mp[++Num] = d[i].r;
    49     }
    50     sort(d+1,d+n+1,cmp);
    51     sort(mp+1,mp+Num+1);
    52     Num = unique(mp+1,mp+Num+1)-mp-1;
    53     for(int i=1;i<=n;i++){
    54     d[i].l = lower_bound(mp+1,mp+Num+1,d[i].l)-mp;
    55     d[i].r = lower_bound(mp+1,mp+Num+1,d[i].r)-mp;
    56     }
    57 }
    58 
    59 void work(){
    60     int lastans = 2e9;
    61     for(int i=1,j=1;i<=n;i++){ // two pointers
    62     T.add(1,d[i].l,d[i].r,1,Num,1);
    63     if(T.Query() == m){
    64         while(j <= i){
    65         T.add(1,d[j].l,d[j].r,1,Num,-1);
    66         if(T.Query() != m){
    67             lastans = min(lastans,d[i].len-d[j].len);
    68             j++;
    69             break;
    70         }
    71         j++;
    72         }
    73     }
    74     while(j <= i && d[i].len - d[j].len > lastans){
    75         T.add(1,d[j].l,d[j].r,1,Num,-1);
    76         j++;
    77     }
    78     }
    79     if(lastans == 2e9) puts("-1");
    80     else printf("%d",lastans);
    81 }
    82 
    83 int main(){
    84     read();
    85     work();
    86     return 0;
    87 }
  • 相关阅读:
    linux screen 命令详解
    centos7 安装docker(手动和脚本安装)换源 卸载
    在linux上安装taiga
    阿里云清除云盾
    Vim
    推荐 130 个令你眼前一亮的网站,总有一个用得着
    索引优化分析 2
    Mysql的主存复制 5
    Mysql锁机制 4
    查询获取分析 3
  • 原文地址:https://www.cnblogs.com/Menhera/p/9123282.html
Copyright © 2011-2022 走看看