题目链接:https://loj.ac/problem/6279

题目描述

给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,询问区间内小于某个值 \(x\) 的前驱(比其小的最大元素)。

输入格式

第一行输入一个数字 \(n\)。

第二行输入 \(n\) 个数字,第 \(i\) 个数字为 \(a_i\),以空格隔开。

接下来输入 \(n\) 行询问,每行输入四个数字 \(opt\)、\(l\)、\(r\)、\(c\),以空格隔开。

若 \(opt=0\),表示将位于\([l,r]\) 之间的数字都加 \(c\)。

若 \(opt=1\),表示询问 \([l,r]\) 中 \(c\) 的前驱的值(不存在则输出 \(-1\))。

输出格式

对于每次询问,输出一行一个数字表示答案。

样例输入

4
1 2 2 3
0 1 3 1
1 1 4 4
0 1 2 2
1 1 2 4

样例输出

3
-1

数据范围与提示

对于 \(100%\) 的数据,\(1 \le n \le 100000, -2^{31} \le others,ans \le 2^{31}-1\)。

解题思路

本题和《数列分块入门 2》思路类似,同样是开一个数组 \(b\) 并块内排序,同样是二分找 \(\le c\) 的最大值。

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int n, m, a[maxn], b[maxn], p[maxn], v[400], op, l, r, c;
inline void chk_max(int &a, int b) {
if (b == -1) return;
if (a == -1 || a < b) a = b;
}
void update_part(int pid) {
int i1 = (pid-1)*m+1, i2 = min(pid*m+1, n+1); // 注意边界条件
for (int i = i1; i < i2; i ++)
b[i] = a[i];
sort(b+i1, b+i2);
}
void add(int l, int r, int c) {
if (p[l] == p[r]) { // 说明在同一个分块,直接更新
for (int i = l; i <= r; i ++) a[i] += c;
update_part(p[l]);
return;
}
if (l % m != 1) { // 说明l不是分块p[l]的第一个元素
for (int i = l; p[i]==p[l]; i ++) {
a[i] += c;
}
update_part(p[l]);
}
else v[p[l]] += c;
if (r % m != 0) { // 说明r不是分块p[r]的最后一个元素
for (int i = r; p[i]==p[r]; i --)
a[i] += c;
update_part(p[r]);
}
else v[p[r]] += c;
for (int i = p[l]+1; i < p[r]; i ++)
v[i] += c;
}
int pre_part(int pid, int c) {
int i1 = (pid-1)*m+1, i2 = min(pid*m+1, n+1);
int id = lower_bound(b+i1, b+i2, c-v[pid]) - (b+i1);
if (id == 0) return -1;
return b[i1+id-1]+v[pid];
}
int get_pre(int l, int r, int c) {
int res = -1;
if (p[l] == p[r]) { // 说明在同一个分块,直接更新
for (int i = l; i <= r; i ++)
if (a[i]+v[p[i]] < c)
chk_max(res, a[i]+v[p[i]]);
return res;
}
if (l % m != 1) { // 说明l不是分块p[l]的第一个元素
for (int i = l; p[i]==p[l]; i ++)
if (a[i]+v[p[i]] < c)
chk_max(res, a[i]+v[p[i]]);
}
else chk_max(res, pre_part(p[l], c));
if (r % m != 0) { // 说明r不是分块p[r]的最后一个元素
for (int i = r; p[i]==p[r]; i --)
if (a[i]+v[p[i]] < c)
chk_max(res, a[i]+v[p[i]]);
}
else chk_max(res, pre_part(p[r], c));
for (int i = p[l]+1; i < p[r]; i ++)
chk_max(res, pre_part(i, c));
return res;
}
int main() {
scanf("%d", &n);
m = sqrt(n);
for (int i = 1; i <= n; i ++) p[i] = (i-1)/m + 1;
for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
for (int i = 1; i <= n; i += m) update_part(p[i]); // 初始化
for (int i = 0; i < n; i ++) {
scanf("%d%d%d%d", &op, &l, &r, &c);
if (op == 0) add(l, r, c);
else printf("%d\n", get_pre(l, r, c));
}
return 0;
}

最新文章

  1. 一种简单的CQRS架构设计及其实现
  2. github push时,要求密码的问题
  3. Ruby的require相关知识
  4. DropDownList
  5. Android 多媒体播放API简介
  6. 编译安装php的配置参数详细解析
  7. Unity-WIKI 之 AnimationToPNG
  8. Hibernate-一对多的关系维护
  9. HDU1435,好开心,稳定婚姻
  10. Redis的hash操作
  11. ElasticSearch安装部署
  12. 高密度Java应用部署的一些实践
  13. initrd.gz的解压和制作
  14. POJ 2653 Pick-up sticks
  15. Linux下利用expect,不用交互模式,直接登陆远程主机
  16. web-php绕过
  17. 使用line_profiler查看api接口函数每行代码执行时间
  18. index_levedb.go
  19. 【20190226】CSS-知识点记录::nth-child,:nth-of-type
  20. 原 HTML5 requestFullScreen&amp;exitFullscreen全屏兼容方案

热门文章

  1. HZOJ 斐波那契(fibonacci)
  2. Android ListView显示底部的分割线
  3. vbox ubuntu虚拟机中加载笔记本内置摄像头
  4. Python 函数参数有冒号 声明后有-&gt; 箭头 返回值注释 参数类型注释
  5. H3C 典型数据链路层标准
  6. 怎样打开.jar格式文件,怎样运行.jar格式文件
  7. poj 3601Tower of Hanoi
  8. 达观数据CTO纪达麒:小标注数据量下自然语言处理实战经验
  9. Native memory allocation (mmap) failed to map 142606336 bytes for committing reserved memory.
  10. ArrayList中remove方法和set(null)的区别