参考:「分块」数列分块入门1 – 9 by hzwer

2

Description

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

思路

每个块内保持升序排列。

则块外暴力统计,块内二分查找分界点。

一些注意点,如:

  1. 要记录下标
  2. 块外暴力修改完之后需要再排序
  3. 在块内二分查找的值是\(c-tag[i]\)而非\(c\).

Code

#include <bits/stdc++.h>
#define maxn 50010
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
typedef long long LL;
int tag[maxn], bl[maxn], n, blo;
struct node {
int x, p;
bool operator < (const node& nd) const { return x < nd.x; }
}a[maxn];
inline int val(int x) { return a[x].x + tag[bl[x]]; }
int query(int l, int r, int c) {
int ret=0;
F(i, bl[l]*blo, min((bl[l]+1)*blo, n)) if (a[i].p>=l&&a[i].p<=r && val(i)<c) ++ret;
if (bl[l]!=bl[r]) F(i, bl[r]*blo, min((bl[r]+1)*blo, n)) if (a[i].p>=l&&a[i].p<=r && val(i)<c) ++ret;
F(i, bl[l]+1, bl[r]) ret += lower_bound(a+i*blo, a+(i+1)*blo, (node){c-tag[i], 0}) - (a+i*blo);
return ret;
}
void add(int l, int r, int c) {
F(i, bl[l]*blo, min((bl[l]+1)*blo,n)) if (a[i].p>=l&&a[i].p<=r) a[i].x+=c;
sort(a+bl[l]*blo, a+min((bl[l]+1)*blo, n));
if (bl[l]!=bl[r]) {
F(i, bl[r]*blo, min((bl[r]+1)*blo, n)) if (a[i].p>=l&&a[i].p<=r) a[i].x+=c;
sort(a+bl[r]*blo, a+min((bl[r]+1)*blo, n));
}
F(i, bl[l]+1, bl[r]) tag[i] += c;
}
int main() {
scanf("%d", &n); blo = sqrt(n);
F(i, 0, n) scanf("%d", &a[i].x), a[i].p = i, bl[i] = i/blo;
int num = (n+blo-1)/blo;
F(i, 0, num-1) sort(a+i*blo, a+(i+1)*blo);
sort(a+(num-1)*blo, a+n);
F(i, 0, n) {
int op, l, r, c;
scanf("%d%d%d%d", &op, &l, &r, &c); --l, --r;
if (op) printf("%d\n", query(l, r, c*c));
else add(l, r, c);
}
return 0;
}

3

Description

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

思路

法一

做法基本同上。

法二

在每个块内用其他数据结构维护,如set,每次修改时,结合原序数组进行修改。

Code

Ver. 1

#include <bits/stdc++.h>
#define maxn 100010
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
typedef long long LL;
int tag[maxn], bl[maxn], n, blo;
struct node {
int x, p;
bool operator < (const node& nd) const { return x < nd.x; }
}a[maxn];
inline int val(int x) { return a[x].x + tag[bl[x]]; }
int query(int l, int r, int c) {
int ans=-1, diff=INT_MAX, temp;
F(i, bl[l]*blo, min((bl[l]+1)*blo, n)) {
if (a[i].p>=l&&a[i].p<=r && (temp=c-val(i))>0 && temp<diff) ans = val(i), diff = temp;
}
if (bl[l]!=bl[r]) F(i, bl[r]*blo, min((bl[r]+1)*blo, n)) {
if (a[i].p>=l&&a[i].p<=r && (temp=c-val(i))>0 && temp<diff) ans = val(i), diff = temp;
}
F(i, bl[l]+1, bl[r]) {
int p = lower_bound(a+i*blo, a+(i+1)*blo, (node){c-tag[i], 0}) - (a+i*blo);
if (p==0) continue;
temp = val(i*blo+p-1);
if (c-temp>0 && c-temp<diff) diff = c-temp, ans = temp;
}
return ans;
}
void add(int l, int r, int c) {
F(i, bl[l]*blo, min((bl[l]+1)*blo,n)) if (a[i].p>=l&&a[i].p<=r) a[i].x+=c;
sort(a+bl[l]*blo, a+min((bl[l]+1)*blo, n));
if (bl[l]!=bl[r]) {
F(i, bl[r]*blo, min((bl[r]+1)*blo, n)) if (a[i].p>=l&&a[i].p<=r) a[i].x+=c;
sort(a+bl[r]*blo, a+min((bl[r]+1)*blo, n));
}
F(i, bl[l]+1, bl[r]) tag[i] += c;
}
int main() {
scanf("%d", &n); blo = sqrt(n);
F(i, 0, n) scanf("%d", &a[i].x), a[i].p = i, bl[i] = i/blo;
int num = (n+blo-1)/blo;
F(i, 0, num-1) sort(a+i*blo, a+(i+1)*blo);
sort(a+(num-1)*blo, a+n);
F(i, 0, n) {
int op, l, r, c;
scanf("%d%d%d%d", &op, &l, &r, &c); --l, --r;
if (op) printf("%d\n", query(l, r, c));
else add(l, r, c);
}
return 0;
}

Ver. 2

然而我写\(T\)了

#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 100010
using namespace std;
typedef long long LL;
int n, blo, bl[maxn], a[maxn], tag[maxn];
multiset<int> st[1010];
void modify(int l, int r, int c) {
F(i, l, min((bl[l]+1)*blo, r+1)) {
st[bl[l]].erase(st[bl[l]].find(a[i]));
st[bl[l]].insert(a[i]+=c);
}
if (bl[l]!=bl[r]) F2(i, bl[r]*blo, r) {
st[bl[r]].erase(st[bl[r]].find(a[i]));
st[bl[r]].insert(a[i]+=c);
}
F(i, bl[l]+1, bl[r]) tag[i] += c;
}
inline int val(int x) { return a[x] + tag[bl[x]]; }
int query(int l, int r, int c) {
int ans=-1;
F(i, l, min((bl[l]+1)*blo, r+1)) {
if (val(i)<c) ans = max(ans, val(i));
}
if (bl[l]!=bl[r]) F2(i, bl[r]*blo, r) {
if (val(i)<c) ans = max(ans, val(i));
}
F(i, bl[l]+1, bl[r]) {
auto it = st[i].lower_bound(c-tag[i]);
if (it==st[i].begin()) continue;
int x;
ans = max(ans, x=*(--it)+tag[i]);
}
return ans;
}
LL read()
{
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main() {
scanf("%d", &n); blo = 1000;
F(i, 0, n) {
a[i] = read();
st[bl[i]=i/blo].insert(a[i]);
}
F(i, 0, n) {
int op, l, r, c;
scanf("%d%d%d%d", &op, &l, &r, &c); --l, --r;
if (op) printf("%d\n", query(l, r, c));
else modify(l, r, c);
}
return 0;
}

loj 6278 6279 数列分块入门 2 3的更多相关文章

  1. LOJ #6279. 数列分块入门 3-分块(区间加法、查询区间内小于某个值x的前驱(比其小的最大元素))

    #6279. 数列分块入门 3 内存限制:256 MiB时间限制:1500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 3   题目描述 给 ...

  2. LOJ 6277:数列分块入门 1(分块入门)

    #6277. 数列分块入门 1 内存限制:256 MiB时间限制:100 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计讨论 3 测试数据 题目描述 给出一 ...

  3. LOJ 6279 数列分块入门3

    嗯... 题目链接:https://loj.ac/problem/6279 这道题在分块的基础上用vc数组记录,然后最后分三块,两边暴力枚举找前驱,中间lower_bound找前驱. AC代码: #i ...

  4. LOJ#6279. 数列分块入门 3

    区间加值还是正常的操作,查找前驱的时候用lower_bound查找,然后范围所在位置的值 #include<map> #include<set> #include<cti ...

  5. #6279. 数列分块入门 3(询问区间内小于某个值 xx 的前驱(比其小的最大元素))

    题目链接:https://loj.ac/problem/6279 题目大意:中文题目 具体思路:按照上一个题的模板改就行了,但是注意在整块查找的时候的下标问题. AC代码: #include<b ...

  6. LibreOj 6279数列分块入门 3 练习了一下set

    题目链接:https://loj.ac/problem/6279 推荐博客:https://blog.csdn.net/qq_36038511/article/details/79725027 这题区 ...

  7. 【LOJ#6278】数列分块2

    题目大意:分块维护一个有 n 个数字的序列,有两种操作:区间加,区间查询小于某个数的元素个数.n <= 50000 预处理阶段:处理出块内元素的相对大小顺序(排序),时间复杂度为 \(O(nlo ...

  8. 【LibreOJ 6278】 数列分块入门 2 (分块)

    题目原址 给出一个长为n的数列,以及n个操作,操作涉及区间加法,询问区间内小于某个值x的元素个数. code: #include<cstdio> #include<iostream& ...

  9. LibreOJ 6279 数列分块入门 3(分块+排序)

    题解:自然是先分一波块,把同一个块中的所有数字压到一个vector中,将每一个vector进行排序.然后对于每一次区间加,不完整的块加好后暴力重构,完整的块直接修改标记.查询时不完整的块暴力找最接近x ...

随机推荐

  1. 使用eclipse导入web项目

    第一步 第二步 第三步 第四步 最后就多了一个web项目

  2. PHP 计算代码运行所占内存和时间

    PHP 计算代码运行所占内存和时间 在PHP开发过程中,写出高质量的代码是很重要的,除了代码必须规范之外,性能也是不可忽视的一方面,那么如果检验一段代码是否高效呢,可通过以下一段php代码来粗略检测 ...

  3. java util - 在java代码中执行javascript代码工具 rhino-1.7.7.jar

    需要 rhino-1.7.7.jar 包 代码示例: package cn.java.mozilla.javascript; import org.mozilla.javascript.Context ...

  4. DRF工程搭建

    环境安装与配置 DRF需要以下依赖: Python (2.7, 3.2, 3.3, 3.4, 3.5, 3.6) Django (1.10, 1.11, 2.0) DRF是以Django扩展应用的方式 ...

  5. Java程序占用实际内存大小

    很多人错误的认为运行Java程序时使用-Xmx和-Xms参数指定的就是程序将会占用的内存,但是这实际上只是Java堆对象将会占用的内存.堆只是影响Java程序占用内存数量的一个因素.要更好的理解你的J ...

  6. Ping过程&ICMP

    1.ICMP(Internet控制消息协议) ICMP=Internet Control Message Protocol 它是TCP/IP协议族的一个子协议 作用:用于在IP主机.路由之间传递控制消 ...

  7. loj6387 「THUPC2018」绿绿与串串 / String

    还是很好做的,大致就是manacher,每个位置为中心的最长回文串要是能抵到最右边就合法,要是能抵到最左边,那这个点的是否合法取决于以这个点为中心的最长回文串的右端点是否合法. #include &l ...

  8. python 使用 vscode 调试

    vscode安装python扩展,在vscode扩展管理器中搜索pyhon, 排名第一的就是我们需要下载的包—python.点击安装后重载窗体 点击调试–打开launch.json的按钮(那个小齿轮的 ...

  9. Kafka 配置参数

    Broker  Configs Property Default Description broker.id   每个broker都可以用一个唯一的非负整数id进行标识:这个id可以作为broker的 ...

  10. Leetcode 599.两个列表的最小索引总和

    两个列表的最小索引总和 假设Andy和Doris想在晚餐时选择一家餐厅,并且他们都有一个表示最喜爱餐厅的列表,每个餐厅的名字用字符串表示. 你需要帮助他们用最少的索引和找出他们共同喜爱的餐厅. 如果答 ...