AT1219 歴史の研究 回滚莫队
可在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。
输入输出样例
5 5
9 8 7 8 9
1 2
3 4
4 4
1 4
2 4
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 歴史の研究 回滚莫队的更多相关文章
- AT1219 歴史の研究[回滚莫队学习笔记]
回滚莫队例题. 这题的意思大概是 设 \(cnt_i\) 为 l ~ r 这个区间 \(i\) 出现的次数 求\(m\) 次询问 求 l~r 的 max {\(a_i\) * \(cnt_i\)} \ ...
- bzoj4241/AT1219 历史研究(回滚莫队)
bzoj4241/AT1219 历史研究(回滚莫队) bzoj它爆炸了. luogu 题解时间 我怎么又在做水题. 就是区间带乘数权众数. 经典回滚莫队,一般对于延长区间简单而缩短区间难的莫队题可以考 ...
- BZOJ4241:历史研究(回滚莫队)
Description IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记.JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件. ...
- BZOJ.4241.历史研究(回滚莫队 分块)
题目链接 \(Description\) 长度为n的数列,m次询问,每次询问一段区间最大的 \(A_i*tm_i\) (重要度*出现次数) \(Solution\) 好像可以用莫队做,但是取max的操 ...
- 「JOISC 2014 Day1」历史研究 --- 回滚莫队
题目又臭又长,但其实题意很简单. 给出一个长度为\(N\)的序列与\(Q\)个询问,每个询问都对应原序列中的一个区间.对于每个查询的区间,设数\(X_{i}\)在此区间出现的次数为\(Sum_{X_{ ...
- BZOJ4241历史研究——回滚莫队
题目描述 IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记.JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件. 日记中记录了连 ...
- 2018.08.14 bzoj4241: 历史研究(回滚莫队)
传送们 简单的回滚莫队,调了半天发现排序的时候把m达成了n... 代码: #include<bits/stdc++.h> #define N 100005 #define ll long ...
- bzoj4241: 历史研究(回滚莫队)
传送门 这是一个叫做回滚莫队的神奇玩意儿 是询问,而且不强制在线,就决定是你了莫队 如果是每次插入一个数是不是很简单? 然而悲剧的是我们莫队的时候不仅要插入数字还要删除数字 那么把它变成只插入不就行了 ...
- 【BZOJ4241】历史研究(回滚莫队)
题目: BZOJ4241 分析: 本校某些julao乱膜的时候发明了个"回滚邹队",大概意思就是某个姓邹的太菜了进不了省队回滚去文化课 回滚莫队裸题qwq(话说这个名字是不是莫队本 ...
随机推荐
- uber_go_guide解析(二)
前言 接上回 正文 错误消息 Go中声明错误有几种方式 errors.New() 简单的声明静态字符串信息的错误 fmt.Errorf 可以格式化插入信息的错误 自己实现 Error() 方法 使用e ...
- 【Java基础】面向对象中
面向对象中 这一章主要涉及面向对象的三大特征,包括封装.继承.多态.(抽象). 封装 程序设计追求"高内聚,低耦合": 高内聚 :类的内部数据操作细节自己完成,不允许外部干涉: 低 ...
- 【JavaWeb】Servlet 程序
Servlet 程序 Servlet Servlet 是在 Web 服务器中运行的小型 Java 程序.Servlet 通常通过 HTTP(超文本传输协议)接收和响应来自 Web 客户端的请求. ...
- Linux 用户操作之用户管理 (用户增删改操作)
目录 添加用户 删除用户 修改用户 切换用户 配置用户密码 查看配置文件 cat /etc/pwsswd 添加用户 可选项 -c comment 指定一段注释性描述. -d 目录 指定用户主目录,如果 ...
- 【Java】运算符(算术、赋值、比较(关系)、逻辑、条件、位运算符)
运算符 文章目录 运算符 1. 算术运算符 2. 赋值运算符 3. 比较运算符 4. 逻辑运算符 5. 条件运算符 6. 位运算符 7. 运算符优先级 8. 运算符操作数类型说明 9.code 算术运 ...
- 【Linux】md5sum 生产所有文件的md5值,并对照目标文件是否相同
现在加入有很多很多文件需要测试md5,想看下是否都传输成功了,如何批量生成文件的md5并且逐条对照呢? 下面来简单介绍下 md5sum这个命令有一个选项"-c" 这个选项的意思是c ...
- CTFshow-萌新赛杂项_签到
查看网页信息 http://game.ctf.show/r2/ 把网页源码下载后发现有大片空白 使用winhex打开 把这些16进制数值复制到文件中 把20替换为0,09替换为1后 得到一串二进制数值 ...
- springAOP的概述及使用
Spring AOP SpringAOP是Spring中非常重要的功能模块之一,该模块提供了面向切面编程,在事务处理,日志记录,安全控制等操作中广泛使用. SpringAOP的基本概念 AOP的概念 ...
- USB充电限流芯片,输出短路关闭,过压关闭
PW1503,PW1502是超低RDS(ON)开关,具有可编程的电流限制,以保护电源源于过电流和短路保护.它具有超温保护以及反向闭锁功能. PW1503,PW1502采用薄型(1毫米)5针薄型SOT2 ...
- html简单基础
标签语法 标签的语法: <标签名 属性1="属性值1" 属性2="属性值2"-->内容部分</标签名> <标签名 属性1=&quo ...