可在vj上提交:https://vjudge.net/problem/AtCoder-joisc2014_c

题意:

IOI 国历史研究的第一人——JOI 教授,最近获得了一份被认为是古代 IOI 国的住民写下的日记。JOI 教授为了通过这份日记来研究古代 IOI 国的生活,开始着手调查日记中记载的事件。

日记中记录了连续 NN 天发生的时间,大约每天发生一件。

事件有种类之分。第 ii 天发生的事件的种类用一个整数 X_iXi​ 表示,X_iXi​ 越大,事件的规模就越大。

JOI 教授决定用如下的方法分析这些日记:

  • 选择日记中连续的几天 [L,R][L,R] 作为分析的时间段;

  • 定义事件 AA 的重要度 W_AWA​ 为 A\times T_AA×TA​,其中 T_ATA​ 为该事件在区间 [L,R][L,R] 中出现的次数。

现在,您需要帮助教授求出所有事件中重要度最大的事件是哪个,并输出其重要度。

注意:教授有多组询问。

输入格式

第一行两个空格分隔的整数 NN 和 QQ,表示日记一共记录了 NN 天,询问有 QQ 次。

接下来一行 NN 个空格分隔的整数表示每天的事件种类。

接下来 QQ 行,每行给出 L,RL,R 表示一组询问。

输出格式

输出共有 QQ 行,每行一个整数,表示对应的询问的答案。

数据范围

对于 100\%100% 的数据,1\le Q,N\le 10^51≤Q,N≤105,1\le X\le 10^91≤X≤109,1\le L\le R\le 10^51≤L≤R≤105。

输入输出样例

输入 #1复制

5 5
9 8 7 8 9
1 2
3 4
4 4
1 4
2 4
输出 #1复制

9
8
8
16
16

题解:

我们首先说一下普通莫队怎么做:
首先就是对区间排序,因为我们需要找一个区间内的最大值,这个我们可以用以变量tmp来记录。
如果要添加一个数,那么我们用cnt数组来记录某个数出现的次数,并更新tmp的值
但是如果要删除一个数,虽然我们的cnt数组还可以通过减去1来保证cnt数组正确性,但是我们没有办法去更新tmp
那么要是保证tmp正确性,我们就必须对这个区间重新遍历一次,而不能在上一个区间的前提下操作。
那么如果这样操作的话,复杂度就是n*n*sqrt(n),相信这个复杂度大多题目都会TLE了

回滚莫队解决它:
首先排序函数要改一下,如果两个查询区间的左边界不在一个块,那就按照左边界从小到大排序,否则那就按照右边界从小到大排序

ll cmp(query a, query b)
{
return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] : a.r < b.r;
}

对于一个查询区间[l,r],我们把l叫做左边界,把r叫做右边界。使用左标记和右标记来在n个数的位置上移动

这样,对于左边界属于一个块(我们把n个数分成sqrt(n)个块)的查询区间,因为这些查询区间的右边界是递增的,所以右标记就只会向右移动,不会向左,就意味着不会出现删除元素的情况

但是这些查询区间的左边界可不一定和右边界的位置对应,也就是说对于右边界添加元素和删除元素的情况都会出现,怎么解决呢?
我们就暴力去解决,每次把左标记移动到一个查询区间的左边界,操作完之后在移动原位置(这一点可以看代码)

for(; belong[que[i].l]==k; ++i) //在同一个块内
{
ll start=que[i].l,last=que[i].r;
ll tmp;
while(r<last) //因为我们的排序函数,所以我们只需要r<last和l>start两种情况
{
++r;
++cnt[typ[r]];
now=max(now,1ll*cnt[typ[r]]*arr[r]);
}
tmp=now;
while(l > start) //将左标记回归到原位置
{
--l;
++cnt[typ[l]];
now = max(now, 1ll * cnt[typ[l]] * arr[l]);
} ans[que[i].id] = now;
while(l < rb[k] + 1)
{
--cnt[typ[l]];
l++;
}
now = tmp;
}

这个复杂度就是n*sqrt(n)。因为每次左标记都是一个固定位置,我们移动到一个查询区间的左边界这个复杂度就是sqrt(n)
因为一共有m个查询,所以m个边界(题目上说了m<=n) 所以最大复杂度就是n*sqrt(n)

然后右边界可能不在这个块内,但是右标记不需要来回移动,它只需要一直向右移动(添加元素),所以复杂度n
因为最多也就sqrt(n)个块,所以复杂度最大就是n*sqrt(n)

所以复杂度也就是n*sqrt(n)

代码:

#include <map>
#include <set>
#include <list>
#include <queue>
#include <deque>
#include <cmath>
#include <stack>
#include <vector>
#include <bitset>
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 2e5+10;
const int INF = 0x3f3f3f3f;
const double PI = 3.1415926;
const long long N = 1000006;
const double eps = 1e-10;
typedef long long ll;
#define mem(A, B) memset(A, B, sizeof(A))
#define lson rt<<1 , L, mid
#define rson rt<<1|1 , mid + 1, R
#define ls rt<<1
#define rs rt<<1|1
#define SIS std::ios::sync_with_stdiget_mod_new(z-x)o(false), cin.tie(0), cout.tie(0)
#define pll pair<long long, long long>
#define lowbit(abcd) (abcd & (-abcd))
#define max(a, b) ((a > b) ? (a) : (b))
#define min(a, b) ((a < b) ? (a) : (b))
inline ll read() //读取整数
{
ll res = 0;
char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c)) res = (res << 1) + (res << 3) + (c ^ 48), c = getchar();
return res;
}
ll arr[maxn],cnt[maxn],cnt2[maxn],typ[maxn],inp[maxn],belong[maxn],lb[maxn],rb[maxn];
ll n,m,sizes,new_size;
ll ans[maxn];
struct query
{
ll l,r,id;
} que[maxn];
ll cmp(query a, query b)
{
return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] : a.r < b.r;
}
int main()
{
n=read(),m=read();
sizes=sqrt(n);
new_size=ceil((double)n/sizes);
for(ll i = 1; i <= new_size; ++i)
{
lb[i] = sizes * (i - 1) + 1;
rb[i] = sizes * i;
for(ll j = lb[i]; j <= rb[i]; ++j)
belong[j] = i;
}
rb[new_size]=n;
for(ll i=1; i<=n; ++i)
arr[i]=inp[i]=read();
sort(inp+1,inp+1+n);
ll tot=unique(inp+1,inp+1+n)-inp-1;
for(ll i=1; i<=n; ++i)
{
typ[i]=lower_bound(inp+1,1+inp+tot,arr[i])-inp;
}
for(ll i=1; i<=m; ++i)
{
que[i].l=read();
que[i].r=read();
que[i].id=i;
}
sort(que+1,que+1+m,cmp);
ll i=1;
for(ll k=1; k<=new_size; ++k)
{
ll l=rb[k]+1,r=rb[k];
ll now=0;
mem(cnt,0);
for(; belong[que[i].l]==k; ++i) //在同一个块内
{
ll start=que[i].l,last=que[i].r;
ll tmp;
if(belong[start]==belong[last]) //特判
{
tmp=0;
for(ll j=start;j<=last;++j)
{
cnt2[typ[j]]=0;
}
for(ll j=start; j<=last; ++j)
{
cnt2[typ[j]]++;
tmp=max(tmp,1ll*cnt2[typ[j]]*arr[j]);
}
ans[que[i].id]=tmp;
continue;
}
while(r<last) //因为我们的排序函数,所以我们只需要r<last和l>start两种情况
{
++r;
++cnt[typ[r]];
now=max(now,1ll*cnt[typ[r]]*arr[r]);
}
tmp=now;
while(l > start)
{
--l;
++cnt[typ[l]];
now = max(now, 1ll * cnt[typ[l]] * arr[l]);
} ans[que[i].id] = now;
while(l < rb[k] + 1)
{
--cnt[typ[l]];
l++;
}
now = tmp;
} }
for(ll i=1; i<=m; ++i) printf("%lld\n",ans[i]);
return 0;
}

AT1219 歴史の研究 回滚莫队的更多相关文章

  1. AT1219 歴史の研究[回滚莫队学习笔记]

    回滚莫队例题. 这题的意思大概是 设 \(cnt_i\) 为 l ~ r 这个区间 \(i\) 出现的次数 求\(m\) 次询问 求 l~r 的 max {\(a_i\) * \(cnt_i\)} \ ...

  2. bzoj4241/AT1219 历史研究(回滚莫队)

    bzoj4241/AT1219 历史研究(回滚莫队) bzoj它爆炸了. luogu 题解时间 我怎么又在做水题. 就是区间带乘数权众数. 经典回滚莫队,一般对于延长区间简单而缩短区间难的莫队题可以考 ...

  3. BZOJ4241:历史研究(回滚莫队)

    Description IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记.JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件. ...

  4. BZOJ.4241.历史研究(回滚莫队 分块)

    题目链接 \(Description\) 长度为n的数列,m次询问,每次询问一段区间最大的 \(A_i*tm_i\) (重要度*出现次数) \(Solution\) 好像可以用莫队做,但是取max的操 ...

  5. 「JOISC 2014 Day1」历史研究 --- 回滚莫队

    题目又臭又长,但其实题意很简单. 给出一个长度为\(N\)的序列与\(Q\)个询问,每个询问都对应原序列中的一个区间.对于每个查询的区间,设数\(X_{i}\)在此区间出现的次数为\(Sum_{X_{ ...

  6. BZOJ4241历史研究——回滚莫队

    题目描述 IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记.JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件. 日记中记录了连 ...

  7. 2018.08.14 bzoj4241: 历史研究(回滚莫队)

    传送们 简单的回滚莫队,调了半天发现排序的时候把m达成了n... 代码: #include<bits/stdc++.h> #define N 100005 #define ll long ...

  8. bzoj4241: 历史研究(回滚莫队)

    传送门 这是一个叫做回滚莫队的神奇玩意儿 是询问,而且不强制在线,就决定是你了莫队 如果是每次插入一个数是不是很简单? 然而悲剧的是我们莫队的时候不仅要插入数字还要删除数字 那么把它变成只插入不就行了 ...

  9. 【BZOJ4241】历史研究(回滚莫队)

    题目: BZOJ4241 分析: 本校某些julao乱膜的时候发明了个"回滚邹队",大概意思就是某个姓邹的太菜了进不了省队回滚去文化课 回滚莫队裸题qwq(话说这个名字是不是莫队本 ...

随机推荐

  1. dotnet高性能buffer

    1 前言 我曾经写过<杂谈.netcore的Buffer相关新类型>的博客,简单介绍过BinaryPrimitives.Span<>,Memory<>,ArrayP ...

  2. python学习笔记 | PyCharm创建文件时自动添加头文件

    File Settings Editor File and Code Templates Python Script 然后在右边的框中写入信息就可以啦: # -*- coding: utf-8 -*- ...

  3. 解决Tengine健康检查引起的TIME_WAIT堆积问题

    简介: 解决Tengine健康检查引起的TIME_WAIT堆积问题 一. 问题背景 "服务上云后,我们的TCP端口基本上都处于TIME_WAIT的状态"."这个问题在线下 ...

  4. MySQL常用的数据类型和字段属性

    数据类型 数值 tinyint 十分小的数据 1个字节 smallint 较小的数据 2个字节 mediumint 中等大小的数据 3个字节 int 标准的整数 4个字节 常用 bigint 较大的数 ...

  5. 【MySQL】DDL数据定义语言的基本用法create、drop和alter(增删改)

    DDL 的基础语法 文章目录 DDL 的基础语法 对数据库进行定义 对数据表进行定义 创建表结构(数据表) 设计工具 修改表结构 小结 参考资料 简单复习一波 SQL必知必会 DDL 的英文全称是 D ...

  6. 优先队列priority_queue排序

    优先队列默认大顶堆,即堆顶元素是最大值 改成小顶堆时: priority_queue<int,vector<int>, greater<int> > Q;//注意最 ...

  7. bash shell关联数组总结

    [原创]本博文为原创博文,引用或转发请注明原始出处和链接:https://www.cnblogs.com/dingbj/p/dict_array.html 什么是关联数组? 关联数组相对于索引数组,又 ...

  8. 2V升3V芯片,输入2V输出3V可达1A

    PW5328B是一个恒定频率, 6引脚 SOT23电流模式升压转换器,用于小型低功耗应用. PW5328B的开关频率为 1.2MHz,允许使用微小的.低成本的电容器和电感器.内部软启动导致小涌流和延长 ...

  9. 注解 @AutoConfigureBefore 和 @AutoConfigureAfter 的用途

    注解 @AutoConfigureBefore 和 @AutoConfigureAfter 的用途 介绍: 如果你想将在SpringBoot项目中的配置类进行排序,那么用到spring-boot-au ...

  10. mysql忽略表中的某个字段不查询

    业务场景 1.表中字段较多 2.查询不需要表中某个字段的数据 语句如下: SELECT CONCAT(' select ',GROUP_CONCAT(COLUMN_NAME),' from ', TA ...