可在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. 白日梦的Elasticsearch笔记(一)基础篇

    目录 一.导读 1.1.认识ES 1.2.安装.启动ES.Kibana.IK分词器 二.核心概念 2.1.Near Realtime (NRT) 2.2.Cluster 2.3.Node 2.4.In ...

  2. Ts有限状态机

    ts版本的有限状态机 最近做小游戏要做切换人物状态,花点时间写了一个有限状态机,使用语言为Ts,也可改成自己的语言 按照目前的逻辑,这个可以继续横向扩展,某些做流程管理 先上预览图 Fsm:状态机类 ...

  3. oop的三大特性和传统dom如何渲染

    OOP的三大特性是什么: 封装 :就是将一个类的使用和实现分开,只保留部分接口和方法与外部联系继承:子类自动继承其父级类中的属性和方法,并可以添加新的属性和方法或者对部分属性和方法进行重写.继承增加了 ...

  4. Flutter 布局类组件:弹性布局(Flex)

    前言 弹性布局允许子组件按照一定比例来分配父容器空间,Flutter中的弹性布局主要通过Flex和Expanded来配合实现. Flex Flex组件可以沿着水平或垂直方向排列子组件,如果你知道主轴方 ...

  5. 关联实现上-jsonpath取值

    举例子: demo01.py import jsonimport requestsimport jsonpathsession = requests.session()get_param_dict={ ...

  6. 【项目实践】手把手带你搞定SSM

    以项目驱动学习,以实践检验真知 前言 现在使用Java后端开发使用的技术栈基本上比较统一:Spring + SpringMVC + Mybatis,即大家常说的SSM.虽然现在流行的做法是使用Spri ...

  7. 【Linux】用find删除大于30天的文件

    1.删除文件命令: find 对应目录 -mtime +天数 -name "文件名" -exec rm -rf {} \; 实例命令:find /opt/soft/log/ -mt ...

  8. Apache目录详解

    Apache的主要目录和配置文件理解 参考链接:http://httpd.apache.org/docs/2.4/misc/security_tips.html 一.Apache主要配置文件注释(演示 ...

  9. pandas数据分析API常用操作

    1.导入数据 df = pd.read_csv( # 该参数为数据在电脑中的路径,可以不填写 filepath_or_buffer='/Users/Weidu/Desktop/sz000002.csv ...

  10. undefined和null区别

    undefined类型只有一个值就是undefined,没有必要显式地声明一个变量为undefined. null类型其实就是一个对象的空指针,所以用typeof null 才会显示为object. ...