时光倒流+暴力+尺取


第一次看到这题,是在神子杏的课堂上

这就是一个裸的双指针,洛咕上多倍经验的题太多了。 ——神子杏

那好,我们就用双指针来考虑这道题。

首先可以发现

  • 答案区间$ (l,r) $ 一定在某两个标记点之间,也就是说,$l-1 $ 应当是一个有标记点,\(r+1\) 也应是一个有标记的点。

证明很显然,假如右端点的右侧没有标记,那么右端点一定可以继续向右延伸。左端点同理。

往数轴上增加标记不好做,考虑从数轴上拿走标记。我们可以预处理出所有标记点都在数轴上时的答案,也就是输出答案的最后一行。关于这一步,我们可以发现暴力枚举每一个可能的答案区间\((l,r)\)的复杂度为\(O(n^2)\),这显然是不能接受的。发现每当我们确定一个左端点l,则随着l的增大,r是单调不降的。基于这一性质,考虑用双指针扫一遍,\(O(n)\)美滋滋。

接下来考虑依次删去每一个标记,即将这一标记的权值设为\(0\),同时统计对应的答案。统计答案的方法同上。但是我们会发现这样单次复杂度最坏是\(O(n)\),不能接受。

还需要注意的是,题目中要求标记个数不大于k,发现k很小,考虑暴力做。可以发现

  • 删除一个标记点时,至多只会影响这个点左侧k个和右侧k个点(想一想,为什么)。

所以我们只需要在每次删除时,以\(O(k)\)的复杂度用双指针来找这个标记点的左右能不能作为答案即可。

继续考虑优化。删除一个标记,我们不仅删除它的权值,而且删除这个标记的在数组存储中的下标,枚举端点的时候直接跳过它。没错,我们可以使用一个链表来维护每一个端点的前驱和后继。在删除标记时,只需修改其前驱后继的关系即可。

最后需要特判一种情况:删除上一个标记点时的答案区间为\((l0,r0)\),删除当前标记点的答案区间为\((l,r)\),两个区间不是包含关系。这时需要将当前的答案取两者中较大的即可。

则总复杂度为\(O(nk)\)

Code

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e+6+100;
const int inf = 0x7f7f7f7f;
struct Data{
int x,a,tim;
};
int n,m,k;
Data opt[maxn];
int tim[maxn];
int ans[maxn];
int pre[maxn],suc[maxn];
inline int read(){
int v=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-f; ch = getchar();}
while(ch>='0'&&ch<='9'){v=(v<<3)+(v<<1)+ch-'0';ch=getchar();}
return v*f;
}
inline bool cmp(Data x,Data y){
return x.x<y.x;
}
int main(){
n=read();m=read();k=read();
for(register int i=1;i<=n;++i){
opt[i].x=read();opt[i].a=read();opt[i].tim = i;
ans[i] = -1;
}
opt[n+1]=Data{-1,inf,0};
opt[n+2]=Data{m+1,inf,0};
sort(opt+1,opt+n+3,cmp);
for(register int i=1;i<=n+2;++i) tim[opt[i].tim] = i;
for(register int l=1,r=1,cnt=0;r<=n+2;++r){
cnt+=opt[r].a;
while(cnt>k){
cnt-=opt[l++].a;
if(l>r) break;;
}
if(k==0) ans[n] = max(ans[n],opt[r].x-opt[r-1].x-2);
else ans[n]=max(ans[n],opt[r+1].x-opt[l-1].x-2);
}
for(register int i=1;i<=n+2;++i){
if(i!=1)pre[i] = i-1;
suc[i] = i+1;
}
for(register int i=n-1;i>=1;--i){
int t=tim[i+1];
opt[t].a=0;
pre[suc[t]] = pre[t];
suc[pre[t]] = suc[t];
int r=t,lim=t;
for(int p=0;p<=k+10;++p){
r=max(pre[r],2);
lim=min(suc[lim],n+2);
}
for(register int l=r,cnt=0;r<=lim;r=suc[r]){
cnt+=opt[r].a;
while(cnt>k){
cnt-=opt[l].a;
l=suc[l];
}
if(k==0) ans[i] = max(ans[i],opt[r].x-opt[pre[r]].x-2);
else ans[i] = max(ans[i],opt[suc[r]].x-opt[pre[l]].x-2);
}
ans[i]=max(ans[i+1],ans[i]);
}
for(register int i=1;i<=n;++i) printf("%d\n",ans[i]);
return 0;
}

洛谷 P6602 数轴的更多相关文章

  1. USACO Section 1.3 题解 (洛谷OJ P1209 P1444 P3650 P2693)

    usaco ch1.4 sort(d , d + c, [](int a, int b) -> bool { return a > b; }); 生成与过滤 generator&& ...

  2. 洛谷AT2046 Namori(思维,基环树,树形DP)

    洛谷题目传送门 神仙思维题还是要写点东西才好. 树 每次操作把相邻且同色的点反色,直接这样思考会发现状态有很强的后效性,没办法考虑转移. 因为树是二分图,所以我们转化模型:在树的奇数层的所有点上都有一 ...

  3. [洛谷P4609] [FJOI2016]建筑师

    洛谷题目链接:[FJOI2016]建筑师 题目描述 小 Z 是一个很有名的建筑师,有一天他接到了一个很奇怪的任务:在数轴上建 \(n\) 个建筑,每个建筑的高度是 \(1\) 到 \(n\) 之间的一 ...

  4. 【洛谷】P1052 过河【DP+路径压缩】

    P1052 过河 题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙 ...

  5. 「洛谷5017」「NOIP2018」摆渡车【DP,经典好题】

    前言 在考场被这个题搞自闭了,那个时候自己是真的太菜了.qwq 现在水平稍微高了一点,就过来切一下这一道\(DP\)经典好题. 附加一个题目链接:[洛谷] 正文 虽然题目非常的简短,但是解法有很多. ...

  6. 洛谷疯狂coding~

    1.关于数学建模思想在coding之中的应用. 将马路作为一条数轴,每棵树的位置作为数轴上的坐标点,再将坐标点与数组的下标联系到一起,完成建模. 2.本题坑点在于对“其中有多少个数,恰好等于集合中另外 ...

  7. 洛谷P1052 过河

    P1052 过河 题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上. 由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青 ...

  8. 洛谷P1712 [NOI2016]区间 尺取法+线段树+离散化

    洛谷P1712 [NOI2016]区间 noi2016第一题(大概是签到题吧,可我还是不会) 链接在这里 题面可以看链接: 先看题意 这么大的l,r,先来个离散化 很容易,我们可以想到一个结论 假设一 ...

  9. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

随机推荐

  1. Centos7源码编译安装LAMP环境

    参考地址:https://www.linuxidc.com/Linux/2018-03/151133.htm

  2. Typora基础使用

    Markdown学习 标题 三级标题 四级标题 字体 Hello,World! Hello,World! Hello,World! Hello,World! 引用 选择狂神说Java,走向人生巅峰 分 ...

  3. python-数据清洗与编码解码

    0x01 join str = 'hk$$yicunyiye$$hello world' print(str.split('$$')) #自己实现 result = '' for i in str.s ...

  4. linux学习(二)认识Linux

    一.Linux系统的组成 linux内核(linus 团队管理) shell:用户与内核交互的接口 文件系统:ext3.ext4等.windows 有 fat32 .ntfs 第三方应用软件 二.Li ...

  5. java中的几种基础排序

    import java.util.Random;import java.util.Arrays; public class Puppy {     public static void main(St ...

  6. 1、了解JVM

    1.JVM.JRE.JDK JVM:是可以将要运行的程序编译成机器语言并去执行的一个平台,具有跨语言.跨平台的特性,运行时需要依赖JRE中的类库 JRE:包含了JVM以及代码运行时的类库,时Java程 ...

  7. Spring学习(五)--Spring的IOC

    1.BeanDefinition在IOC的注册 当BeanDefinition完成载入和解析之后,用户定义的BeanDefinition在IOC容器中已经建立自己的数据结构和数据表示,但是无法使用,需 ...

  8. 使用 jsDelivr 免费加速 GitHub Pages 博客的静态资源(二)

    之前写过一篇 使用 jsDelivr 免费加速 GitHub Pages 博客的静态资源,在那之后,又陆续想到并实施了几点利用 jsDelivr 进一步加速静态资源加载的措施,新起一篇作为记录和分享. ...

  9. 实验一 C运行环境与最简单的程序设计

    实验一: #include<stdio.h> int main() {   int a1,a2;   int sum;   a1 =123;   a2 = 456;   sum = a1+ ...

  10. Opencv的imread用法

    所有参考来自网上仅仅做学习记录用,具体正确性需要在具体项目各自验证,不涉及具体错误代码处理调试等问题,欢迎发现发现问题~ 参考: 1. https://blog.csdn.net/LiheZhu/ar ...