【BZOJ4241】历史研究(回滚莫队)
题目:
分析:
本校某些julao乱膜的时候发明了个“回滚邹队”,大概意思就是某个姓邹的太菜了进不了省队回滚去文化课
回滚莫队裸题qwq(话说这个名字是不是莫队本人起的啊这么萌zui
首先看到题询问区间信息+没强制在线,妥妥的莫队。然而朴素的莫队(开个桶记每种事件当前的重要度,用set或者堆之类维护一下答案)要\(O(n\sqrt n \log n)\),直接T了……
兔崽子给我说有一种神奇的分块做法,然而我太菜了还没写,先挖个坑以后再补。
然后我去网上orz题解,看到一种叫“回滚莫队”的神奇的东西。可以发现,朴素莫队的问题在于区间变长的时候可以\(O(1)\)更新答案,但是为了维护区间变短必须要套个\(\log n\)的数据结构。所以,如果不存在区间变短的情况,就可以直接\(O(1)\)更新答案,总复杂度\(O(n\sqrt n)\)了。
考虑左端点在同一块中的所有询问,它们的右端点是单调非降的。对于左右端点在同一块中的询问,直接暴力查询即可。否则,设左端点所在块的下一块开头为\(pos\),用一个指针\(r\)往右扫,统计\([pos,r]\)的答案。此时还有\([l,pos)\)的答案没有统计。对于每个询问,暴力\(O(\sqrt n)\)统计这部分答案,最后对两部分答案取\(max\)即可。具体参见代码。
代码:
朴素莫队(TLE):
(一开始离散化写炸了WA了几发……菜死了)
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <queue>
#include <cmath>
#define _ 0
using namespace std;
namespace zyt
{
template<typename T>
inline bool read(T &x)
{
char c;
bool f = false;
x = 0;
do
c = getchar();
while (c != EOF && c != '-' && !isdigit(c));
if (c == EOF)
return false;
if (c == '-')
f = true, c = getchar();
do
x = x * 10 + c - '0', c = getchar();
while (isdigit(c));
if (f)
x = -x;
return true;
}
template<typename T>
inline void write(T x)
{
char buf[20];
char *pos = buf;
if (x < 0)
putchar('-'), x = -x;
do
*pos++ = x % 10 + '0';
while (x /= 10);
while (pos > buf)
putchar(*--pos);
}
typedef long long ll;
const int N = 1e5 + 10, Q = 1e5 + 10;
int n, q, block, belong[N], arr[N], tmp[N];
ll ans[N];
struct _ask
{
int l, r, id;
bool operator < (const _ask &b) const
{
return belong[l] == belong[b.l] ? r < b.r : belong[l] < belong[b.l];
}
}ask[Q];
namespace Mo_Algorithm
{
priority_queue<ll> pq, del;
ll num[N];
void update(const int pos, const int x)
{
del.push(num[pos]);
num[pos] += (ll)tmp[pos] * x;
pq.push(num[pos]);
while (!del.empty() && pq.top() == del.top())
pq.pop(), del.pop();
}
void solve(const int maxx)
{
int l = 1, r = 1;
for (int i = 1; i <= maxx; i++)
pq.push(0);
update(arr[1], 1);
for (int i = 1; i <= q; i++)
{
while (l < ask[i].l)
update(arr[l++], -1);
while (l > ask[i].l)
update(arr[--l], 1);
while (r < ask[i].r)
update(arr[++r], 1);
while (r > ask[i].r)
update(arr[r--], -1);
ans[ask[i].id] = pq.top();
}
}
}
int work()
{
read(n), read(q);
block = pow(n, 0.5);
for (int i = 1; i <= n; i++)
{
read(arr[i]), tmp[i] = arr[i];
belong[i] = (i - 1) / block + 1;
}
sort(tmp + 1, tmp + n + 1);
int cnt = unique(tmp + 1, tmp + n + 1) - tmp;
for (int i = 1; i <= n; i++)
arr[i] = lower_bound(tmp + 1, tmp + cnt, arr[i]) - tmp;
for (int i = 1; i <= q; i++)
{
read(ask[i].l), read(ask[i].r);
ask[i].id = i;
}
sort(ask + 1, ask + q + 1);
Mo_Algorithm::solve(cnt);
for (int i = 1; i <= q; i++)
write(ans[i]), putchar('\n');
return (0^_^0);
}
}
int main()
{
return zyt::work();
}
回滚莫队(AC):
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <queue>
#include <cmath>
#define _ 0
using namespace std;
namespace zyt
{
template<typename T>
inline bool read(T &x)
{
char c;
bool f = false;
x = 0;
do
c = getchar();
while (c != EOF && c != '-' && !isdigit(c));
if (c == EOF)
return false;
if (c == '-')
f = true, c = getchar();
do
x = x * 10 + c - '0', c = getchar();
while (isdigit(c));
if (f)
x = -x;
return true;
}
template<typename T>
inline void write(T x)
{
char buf[20];
char *pos = buf;
if (x < 0)
putchar('-'), x = -x;
do
*pos++ = x % 10 + '0';
while (x /= 10);
while (pos > buf)
putchar(*--pos);
}
typedef long long ll;
const int N = 1e5 + 10, Q = 1e5 + 10;
int n, q, block, belong[N], arr[N], tmp[N];
ll ans[N];
struct _ask
{
int l, r, id;
bool operator < (const _ask &b) const
{
return belong[l] == belong[b.l] ? r < b.r : belong[l] < belong[b.l];
}
}ask[Q];
inline int begin(const int a)
{
return (a - 1) * block + 1;
}
namespace Mo_Algorithm
{
ll solve_small(const int l, const int r)
{
static ll num[N];
ll ans = 0;
for (int i = l; i <= r; i++)
ans = max(ans, num[arr[i]] += tmp[arr[i]]);
for (int i = l; i <= r; i++)
num[arr[i]] = 0;
return ans;
}
void solve(const int maxx)
{
static ll num[N];
ll now = 0;
int l, r, lbegin;
for (int i = 1; i <= q; i++)
{
if (belong[ask[i].l] != belong[ask[i - 1].l])
{
memset(num, 0, sizeof(ll[maxx + 1]));
lbegin = begin(belong[ask[i].l] + 1), l = lbegin, r = lbegin - 1;
now = 0;
}
if (belong[ask[i].l] == belong[ask[i].r])
ans[ask[i].id] = solve_small(ask[i].l, ask[i].r);
else
{
while (r < ask[i].r)
{
++r;
now = max(now, num[arr[r]] += tmp[arr[r]]);
}
ll bck = now;
while (l > ask[i].l)
{
--l;
now = max(now, num[arr[l]] += tmp[arr[l]]);
}
ans[ask[i].id] = now;
while (l < lbegin)
{
num[arr[l]] -= tmp[arr[l]];
++l;
}
now = bck;
}
}
}
}
int work()
{
read(n), read(q);
block = pow(n, 0.5);
for (int i = 1; i <= n; i++)
{
read(arr[i]), tmp[i] = arr[i];
belong[i] = (i - 1) / block + 1;
}
sort(tmp + 1, tmp + n + 1);
int cnt = unique(tmp + 1, tmp + n + 1) - tmp;
for (int i = 1; i <= n; i++)
arr[i] = lower_bound(tmp + 1, tmp + cnt, arr[i]) - tmp;
for (int i = 1; i <= q; i++)
{
read(ask[i].l), read(ask[i].r);
ask[i].id = i;
}
sort(ask + 1, ask + q + 1);
Mo_Algorithm::solve(cnt);
for (int i = 1; i <= q; i++)
write(ans[i]), putchar('\n');
return (0^_^0);
}
}
int main()
{
return zyt::work();
}
【BZOJ4241】历史研究(回滚莫队)的更多相关文章
- BZOJ4241:历史研究(回滚莫队)
Description IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记.JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件. ...
- BZOJ4241历史研究——回滚莫队
题目描述 IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记.JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件. 日记中记录了连 ...
- bzoj4241/AT1219 历史研究(回滚莫队)
bzoj4241/AT1219 历史研究(回滚莫队) bzoj它爆炸了. luogu 题解时间 我怎么又在做水题. 就是区间带乘数权众数. 经典回滚莫队,一般对于延长区间简单而缩短区间难的莫队题可以考 ...
- BZOJ.4241.历史研究(回滚莫队 分块)
题目链接 \(Description\) 长度为n的数列,m次询问,每次询问一段区间最大的 \(A_i*tm_i\) (重要度*出现次数) \(Solution\) 好像可以用莫队做,但是取max的操 ...
- 「JOISC 2014 Day1」历史研究 --- 回滚莫队
题目又臭又长,但其实题意很简单. 给出一个长度为\(N\)的序列与\(Q\)个询问,每个询问都对应原序列中的一个区间.对于每个查询的区间,设数\(X_{i}\)在此区间出现的次数为\(Sum_{X_{ ...
- 【题解】BZOJ4241: 历史研究(魔改莫队)
[题解]BZOJ4241: 历史研究(魔改莫队) 真的是好题啊 题意 给你一个序列和很多组询问(可以离线),问你这个区间中\(\max\){元素出现个数\(\times\)元素权值} IOI国历史研究 ...
- AT1219 歴史の研究 回滚莫队
可在vj上提交:https://vjudge.net/problem/AtCoder-joisc2014_c 题意: IOI 国历史研究的第一人--JOI 教授,最近获得了一份被认为是古代 IOI 国 ...
- AT1219 歴史の研究[回滚莫队学习笔记]
回滚莫队例题. 这题的意思大概是 设 \(cnt_i\) 为 l ~ r 这个区间 \(i\) 出现的次数 求\(m\) 次询问 求 l~r 的 max {\(a_i\) * \(cnt_i\)} \ ...
- 2018.08.14 bzoj4241: 历史研究(回滚莫队)
传送们 简单的回滚莫队,调了半天发现排序的时候把m达成了n... 代码: #include<bits/stdc++.h> #define N 100005 #define ll long ...
随机推荐
- Python初学者容易忽略的一些细节
1.Python中当让给变量1赋值上变量2的值时,变量1直接指向值在内存中存储的地址,即变量1存储的是变量2的值而不是指向变量 2."""的用法 1.多行注释 2.多行输 ...
- Greek symbols --Latex
$\propto$ \propto $\infty$ \infty $\ne$ \ne $\approx$ \approx $\sim$ : \sim --- same ...
- 洛谷 2146 [NOI2015]软件包管理器
[题解] 每个软件只依赖另一个软件,且依赖关系不构成环,那么很容易想到这是树形结构. 我们用1表示以安装,用0表示未安装或已卸载:那么安装一个软件,就是把它到树根的路径上所有的点都改为1:卸载一个软件 ...
- 洛谷 2173 BZOJ 2816 [ZJOI2012]网络
[题解] 明显的LCT模板题,c种颜色就开c棵LCT好了.. #include<cstdio> #include<algorithm> #define N 100010 #de ...
- PAT 1123 Is It a Complete AVL Tree
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child sub ...
- BZOJ 4006 Luogu P3264 [JLOI2015]管道连接 (斯坦纳树、状压DP)
题目链接: (bzoj)https://www.lydsy.com/JudgeOnline/problem.php?id=4006 (luogu)https://www.luogu.org/probl ...
- maven profile多环境自动切换配置,配置分离,排除文件
痛点: 在java开发的过程中,我们经常要面对各种各样的环境,比如开发环境,测试环境,正式环境,而这些环境对项目的需求也不相同. 在此之前,我们往往需要手动去修改相对应的配置文件然后打成war,才能部 ...
- noip模拟赛 三角形
[问题描述] 平面上有N条直线,用方程Aix + Biy +Ci =0表示.这些直线没有三线共点的.现在要你计算出用这些直线可以构造出多少三角形? 输入: 第1行:一个整数N(1 ≤ N≤ 30000 ...
- noip模拟赛 水管工的难题
[问题描述]你是一名优秀的水管工. 一天你遇到了一个棘手的难题. 你需要在一个长方体状的房间内连接一条贯穿房间内部的水管.房间的长为 X,宽为 Y,高为 Z, 整个房间可以看成是 X×Y×Z个小立方体 ...
- BAT、网易、京东等如何做大数据风控的?
大数据风控目前应该是前沿技术在金融领域的最成熟应用,相对于智能投顾.区块链等还在初期的金融科技应用,大数据风控目前已经在业界逐步普及,从BATJ这样的大企业,到交易规模比较大的网贷平台,再到做现金贷. ...