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=0x7f7f7f7f;
  9
 10 struct Range
 11 {
 12     int left,right;
 13     int len;
 14     void assign(int l,int r) { left=l; right=r; len=r-l; }
 15 };
 16
 17 struct SegTree
 18 {
 19     struct Node
 20     {
 21         int val=0; //max-val
 22         int tag=0;
 23         int total() { return val+tag; }
 24     };
 25     Node node[maxN<<2];
 26     int size;
 27     int _val;
 28
 29     void update(int cur,int right)
 30     {
 31         node[cur].val = std::max(node[cur+1].total(),node[right].total());
 32     }
 33     void add(int L,int R,int val)
 34     {
 35         _val=val;
 36         __add(0,L,R+1,0,size);
 37     }
 38     void __add(int cur,int rL,int rR,int nL,int nR)
 39     {
 40         if(rL<=nL && rR>=nR)
 41         {
 42             node[cur].tag+=_val;
 43             return;
 44         }
 45         int mid=(nL+nR)>>1;
 46         int right=cur+((mid-nL)<<1);
 47         if(rL<mid) __add(cur+1,rL,rR,nL,mid);
 48         if(rR>mid) __add(right,rL,rR,mid,nR);
 49         update(cur,right);
 50     }
 51     int askAll() { return node[0].total(); }
 52 };
 53
 54 Range rg[maxN];
 55 SegTree segt;
 56
 57 int N,M;
 58 int buf[maxN<<1];
 59 int valNum;
 60
 61 void input()
 62 {
 63     scanf("%d%d",&N,&M);
 64     int tl,tr;
 65     for(int i=0;i<N;i++)
 66     {
 67         scanf("%d%d",&tl,&tr);
 68         buf[i<<1]=tl;
 69         buf[(i<<1)+1]=tr;
 70         rg[i].assign(tl,tr);
 71     }
 72 }
 73
 74 void discretize()
 75 {
 76     std::sort(buf,buf+(N<<1));
 77     valNum=std::unique(buf,buf+(N<<1))-buf;
 78     for(int i=0;i<N;i++)
 79     {
 80         rg[i].left=std::lower_bound(buf,buf+valNum,rg[i].left)-buf;
 81         rg[i].right=std::lower_bound(buf,buf+valNum,rg[i].right)-buf;
 82     }
 83 }
 84
 85 int solve()
 86 {
 87     int res=inf;
 88     auto cmpIdx=[](const Range& A,const Range& B)->bool { return A.len<B.len; };
 89     std::sort(rg,rg+N,cmpIdx);
 90     discretize();
 91     segt.size=valNum;
 92     int head=-1,tail=-1;
 93     while(1)
 94     {
 95         while((++head)<N && segt.askAll()<M)
 96             segt.add(rg[head].left,rg[head].right,1);
 97         if(segt.askAll()<M) break;
 98         else --head;
 99         while(segt.askAll()==M)
100         {
101             ++tail;
102             res=std::min(res,rg[head].len-rg[tail].len);
103             segt.add(rg[tail].left,rg[tail].right,-1);
104         }
105     }
106     return (res==inf)?-1:res;
107 }
108
109 int main()
110 {
111     input();
112     printf("%d\n",solve());
113     return 0;
114 }
时间: 2024-08-03 09:07:25

UOJ222 NOI2016 区间 线段树+FIFO队列的相关文章

【BZOJ-2892&amp;1171】强袭作战&amp;大sz的游戏 权值线段树+单调队列+标记永久化+DP

2892: 强袭作战 Time Limit: 50 Sec  Memory Limit: 512 MBSubmit: 45  Solved: 30[Submit][Status][Discuss] Description 在一个没有冬马的世界里,经历了学园祭后的春希着急着想要见到心爱的雪菜.然而在排队想见雪菜的fans太多了,春希一时半会凑不到雪菜面前. 作为高帅富,这样的问题怎么能难倒春希?春希从武也手中拿到了取自金闪闪宝库里的多啦A梦的传话筒,并且给每一个排队的fans都发了一个传话筒. 于

Poj3225Help with Intervals区间线段树

这题不说了,都是泪.这题也是拆点. #include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <set&g

BZOJ 1012 线段树||单调队列

非常裸的线段树  || 单调队列: 假设一个节点在队列中既没有时间优势(早点入队)也没有值优势(值更大),那么显然不管在如何的情况下都不会被选为最大值. 既然它仅仅在末尾选.那么自然能够满足以上的条件. 线段树 #include "stdio.h" #include "string.h" struct node { int l,r,Max; }data[800010]; int Max(int a,int b) { if (a<b) return b; els

【BZOJ3110】【Zjoi2013】K大数查询 树套树 权值线段树套区间线段树

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43020009"); } 题解: 外层权值线段树,内层区间线段树可解. 权值都是1~n,就不用离散化了. 我写了标记永久化. 其它心得神马的: 天生对树形数据结构无爱. 第一次写树套树,终于知道是怎么回事了. (只针对本题) 就是外层每个点都表示了一段

pojBuy Tickets2828线段树(队列中倒序插队)

这题开始的思路就是模拟:就像数组中插点一样,每一个想买票的人都想往前插队! 但是这样的话肯定TLE, 看了别人的思路之后才恍然大悟! 正解: 将开始的正序插入,变成倒序插入,这样的话,想一想:第 i 个人想要插在 p[i] 的位置上,那么就要保证所插入的位置之前一定要有 p[i]-1个空位!因为一定会有p[j]<p[i] (0<=p[j]<=j,每个人都想往前插队) 的第j个人插在p[i]的位置的前边! 如果i<j; && p[i]==p[j], 倒序插入中,第j个

BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)

题目大意:有一些位置,这些位置上可以放若干个数字.现在有两种操作. 1.在区间l到r上添加一个数字x 2.求出l到r上的第k大的数字是什么 思路:这种题一看就是树套树,关键是怎么套,怎么写.(话说我也不会来着..)最容易想到的方法就是区间线段树套一个权值线段树,但是区间线段树上的标记就会变得异常复杂.所以我们就反过来套,用权值线段树套区间线段树.这样修改操作在外线段树上就变成了单点修改,外线段树就不用维护标记了.在里面的区间线段树上维护标记就容易多了.具体实现见代码. CODE: #includ

【BZOJ-4653】区间 线段树 + 排序 + 离散化

4653: [Noi2016]区间 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 107  Solved: 70[Submit][Status][Discuss] Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就是使得存在一个 x,使得对于每一个被选中的区间 [li,ri],都有 li≤x≤ri. 对于一个合法的选

bzoj 1171 大sz的游戏&amp; 2892 强袭作战 (线段树+单调队列+永久性flag)

大sz的游戏 Time Limit: 50 Sec  Memory Limit: 357 MBSubmit: 536  Solved: 143[Submit][Status][Discuss] Description 大sz最近在玩一个由星球大战改编的游戏.话说绝地武士当前共控制了N个星球.但是,西斯正在暗处悄悄地准备他们的复仇计划.绝地评议会也感觉到了这件事.于是,准备加派绝地武士到各星球防止西斯的突袭.一个星球受到攻击以后,会尽快通知到总基地.需要的时间越长的星球就需要越多绝地武士来防御.为

luogu 1712 区间(线段树+尺取法)

题意:给出n个区间,求选择一些区间,使得一个点被覆盖的次数超过m次,最小的花费.花费指的是选择的区间中最大长度减去最小长度. 坐标值这么大,n比较小,显然需要离散化,需要一个技巧,把区间转化为半开半闭区间,然后线段树的每一个节点表示一个半开半闭区间. 接着我们注意到需要求最小的花费,且这个花费只与选择的区间集合中的最大长度和最小长度有关. 这意味着如果最大长度和最小长度一定,我们显然是需要把中间长度的区间尽量的选择进去使答案不会变的更劣. 不妨把区间按长度排序,枚举每个最小长度区间,然后最大区间