BZOJ4241: 历史研究(回滚莫队)
时间:2022-06-11
本文章向大家介绍BZOJ4241: 历史研究(回滚莫队),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题意
给出$n$个数,每次询问区间$[L, R]$内 每个数*出现次数 的最大值
Sol
回滚莫队,名字真萌qwq
考虑如果用正常莫队的话我们是无法删除的,因为一旦删除了最大元素就无法找到次大元素
这时候有人提出了一种新的计算方式
思想很简单:对于每个询问按照左端点的块的编号进行排序,相同的话按又端点排序
然后暴力计算每个块。
如果询问的两个端点在同一个块中,直接暴力计算,时间复杂度$O(sqrt{n})$
如果不在同一个块中,这时候右端点是不断递增的,因此暴力计算右端点的复杂度为$O(n)$
但是左端点的位置在块内可是飘忽不定的啊qwq
简单,每次询问之后把左端点移动到所在块的最右段即可,每次计算左端点的复杂度为$O(sqrt{n})$
因为有$sqrt{n}$个块,因此总的时间复杂度为$O(sqrt{n}n)$
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define LL long long
using namespace std;
const int MAXN = 1e5 + 10, INF = 1e9 + 7;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, Q;
LL out[MAXN], ans;
int be[MAXN], date[MAXN], cnt[MAXN], a[MAXN], tot, base, num;
struct Query {
int l, r, id;
bool operator < (const Query &rhs) const {
return be[l] == be[rhs.l] ? r < rhs.r : be[l] < be[rhs.l];
}
}q[MAXN];
LL solve(int l, int r) {
static int tim[MAXN]; LL ans = 0;
for(int i = l; i <= r; i++) tim[a[i]] = 0;
for(int i = l; i <= r; i++) tim[a[i]]++, ans = max(ans, 1ll * tim[a[i]] * date[a[i]]);
return ans;
}
void Add(int x) {
cnt[a[x]]++;
ans = max(ans, 1ll * cnt[a[x]] * date[a[x]]);
}
void Del(int x) {
cnt[a[x]]--;
}
int Get(int i, int id) {
int R = min(N, id * base), ql = R + 1, qr = ql - 1; ans = 0;
memset(cnt, 0, sizeof(cnt));
for(; be[q[i].l] == id; i++) {
if(be[q[i].l] == be[q[i].r]) {out[q[i].id] = solve(q[i].l, q[i].r); continue;}
while(qr < q[i].r) Add(++qr);
LL cur = ans;
while(ql > q[i].l) Add(--ql);
out[q[i].id] = ans;
while(ql < R + 1) Del(ql++);//每次询问完之后重新统计答案
ans = cur;
}
return i;
}
main() {
//freopen("4241.in", "r", stdin);
//freopen("4241.out", "w", stdout);
N = read(); Q = read(); base = sqrt(N);
for(int i = 1; i <= N; i++) {
a[i] = date[i] = read(); be[i] = (i - 1) / base + 1;
num = max(num, be[i]);
}
sort(date + 1, date + N + 1);
int tot = unique(date + 1, date + N + 1) - date - 1;
for(int i = 1; i <= N; i++) a[i] = lower_bound(date + 1, date + N + 1, a[i]) - date;
for(int i = 1; i <= Q; i++) q[i].l = read(), q[i].r = read(), q[i].id = i;
sort(q + 1, q + Q + 1);
for(int i = 1, id = 1; id <= num; id++)
i = Get(i, id);
for(int i = 1; i <= Q; i++)
printf("%lldn", out[i]);
return 0;
}
/*
2
3 2
1 2 3
2 2
1 3
3 2
1 2 3
2 2
1 3
*/
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- jQuery点击click()事件
- 大点干!早点散----------深入剖析LVS负载均衡群集原理
- javascript中元素的scrollLeft和scrollTop属性说明
- 大点干!早点散----------LVS负载均衡之LVS-NAT部署实战
- 大点干!早点散----------负载均衡LVS-DR群集部署
- 大点干!早点散----------群集负载均衡LVS DR+keepalived部署实战
- Java字符串所占字节数的小总结
- Java类加载机制详解
- 详解Java注解(Annotation)
- 你不知道的Synchronized
- 从Java并发集合看锁优化策略
- Java常用并发容器总结(二)
- Java常用并发容器总结(一)
- Java常用并发容器总结(三)
- Java常用并发容器总结(四)