【题解】BZOJ4241: 历史研究(魔改莫队)

真的是好题啊

题意

给你一个序列和很多组询问(可以离线),问你这个区间中\(\max\){元素出现个数\(\times\)元素权值}

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

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

事件有种类之分。第i天(1<=i<=N)发生的事件的种类用一个整数Xi表示,Xi越大,事件的规模就越大。

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

\1. 选择日记中连续的一些天作为分析的时间段

\2. 事件种类t的重要度为t*(这段时间内重要度为t的事件数)

\3. 计算出所有事件种类的重要度,输出其中的最大值

现在你被要求制作一个帮助教授分析的程序,每次给出分析的区间,你需要输出重要度的最大值。

题解

和区间元素出现个数有关,先考虑一下莫队。莫队维护了元素出现个数,现在要知道元素\(\times\)权值最大值。

可以发现,你向莫队记录的答案中添加数是可以的,可以正确维护最大值(请意会:ans=max(ans,(ll)data[i]*cnt[i]);),但是对于要删除元素来说不行(你莫队套别的数据结构也不行,超时),所以我们的莫队仅仅支持添加元素。

只能够添加元素的莫队?那能不能魔改一下莫队?

考虑将询问按照莫队一样的方式将询问分块,总共有\(O(\sqrt n)\)块,每一块询问相互独立。对于每一块询问,和莫队一样,按照右端点升序排序。

  • 先考虑一个询问右端点怎么搞定: 我们搞个指针一直向右增加,维护一个\(cnt[]\)数组。这样的复杂度是\(O(n)\)的,因为这个指针不会回退。

  • 再考虑左端点怎么搞定: 直接暴力统计。我们让之前那个指针从当前块右端点出发向右。现在块右端点右边边的\(cnt[]\)可以得到了。

    但是我们还差块右端点左边的贡献。这部分以之前那个\(cnt[]\)为基础直接暴力统计,因为这里仍然是只向莫队添加元素,所以可以统计答案。由于是莫队的方式询问分块,对于每个询问,暴力统计的复杂度不超过\(O(\sqrt n)\)。

但是可能询问区间就小于\(\sqrt n\),为了防止我们讨论边界情况,这部分询问直接读入的时候就处理了。

分析一下复杂度:

  • 对于每个询问,暴力统计部分是\(O(\sqrt n)\),这部分复杂度\(O(n\sqrt n)\)
  • 对于每个块,指针向右移动\(O(n)\)的,这部分复杂度\(O(n\sqrt n)\)
  • 对于那种小询问,暴力统计\(O(n\sqrt n)\)的
  • 其实要离散化,但是我们不需要按照大小离散化,直接哈希\(O(n)\) 。(bzoj不支持,只能用map)

总复杂度\(O(n\sqrt n)\)

这道题实际上提供了如何写只支持添加/删除操作的莫队的算法。普适性很广。

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map> using namespace std; typedef long long ll;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57)f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
} struct E{
int l,r,id;
E(){l=r=0;}
E(const int&a,const int&b,const int&c){l=a;r=b;id=c;}
inline bool operator <(const E&a)const{return r<a.r;}
};
const int maxn=1e5+5;
int cnt0,n,m,N;
int be[maxn],cnt[maxn],arc[maxn],data[maxn];
ll ans[maxn],now;
map<int,int> s0;
vector<int> s;
vector<E> ve[355]; inline void add(const int&pos,const int&tag){
cnt[data[pos]]+=tag;
if(1ll*cnt[data[pos]]*arc[data[pos]]>now) now=1ll*cnt[data[pos]]*arc[data[pos]];
} int main(){
n=qr(); m=qr(); N=sqrt(n-1)+1;
for(register int t=1;t<=n;++t){
data[t]=qr();
if(s0.find(data[t])==s0.end()) s0[data[t]]=++cnt0,arc[cnt0]=data[t];
data[t]=s0[data[t]];
}
for(register int t=1;t<=n;++t) be[t]=(t-1)/N+1;
for(register int t=1,t1,t2;t<=m;++t) {
t1=qr(),t2=qr();
if(t2-t1-5<N){
now=0;
for(register int t=t1;t<=t2;++t) add(t,1),s.push_back(data[t]);
for(register int t=0,ed=s.size();t<ed;++t) --cnt[s[t]];
ans[t]=now; s.clear();
continue;
}
ve[be[t1]].push_back(E(t1,t2,t));
}
for(register int t=1;t<=be[n];++t){
if(ve[t].empty()) continue;
memset(cnt,0,sizeof cnt);
sort(ve[t].begin(),ve[t].end());
int R=N*t,st=R; ll tnow=now=0;
for(register int i=0,ed=ve[t].size();i<ed;++i){
register E f=ve[t][i];
while(R<f.r) add(++R,1);
tnow=now;
for(register int t=st;t>=f.l;--t) add(t,1),s.push_back(data[t]);
for(register int t=0,ed=s.size();t<ed;++t) --cnt[s[t]];
ans[f.id]=now; now=tnow; s.clear();
}
}
for(register int t=1;t<=m;++t) printf("%lld\n",ans[t]);
return 0;
}

【题解】BZOJ4241: 历史研究(魔改莫队)的更多相关文章

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

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

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

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

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

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

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

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

  5. LOJ2874 JOISC2014 历史研究 分块、莫队

    传送门 看到出现次数自然地考虑莫队. 但是发现如果需要删除并动态维护答案的话,则要用一个堆来维护答案,增加了一个\(log\).但是加入操作却没有这个\(log\),所以我们考虑避免删除操作. 分块, ...

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

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

  7. [JOISC2014]歴史の研究/[BZOJ4241]历史研究

    [JOISC2014]歴史の研究/[BZOJ4241]历史研究 题目大意: 一个长度为\(n(n\le10^5)\)的数列\(A(A_i\le10^9)\),定义一个元素对一个区间\([l,r]\)的 ...

  8. BZOJ4241历史研究题解--回滚莫队

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=4241 分析 这题就是求区间权值乘以权值出现次数的最大值,一看莫队法块可搞,但仔细想想,莫 ...

  9. BZOJ4241 历史研究 莫队 堆

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目 Description IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记.JO ...

随机推荐

  1. ubuntu 下编译glew (opengl扩展库)

    最近在研究咋样在QT 下使用opengl 扩展库glew.首先需要明白的是QT中对glut等库进行了封装,但是对glew和glfw等库需要自己编译后使用. 安装步骤: 1.下载Ubuntu下的glew ...

  2. Hbase数据模型 列族

  3. @codechef - BIKE@ Chef and Bike

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 输入 n(n ≤ 22) 个点,m(m ≤ 8000) 个边.每 ...

  4. 全文索引——CONTAINS 语法

    Like直接在数据据中查找可以查到所有所需记录但是会扫描整个表会影响性能CONTAINS是基于全文索引进行查询,查询结果受系统全文索引分词的方法影响查询结果会不全.Select * FROM A Wh ...

  5. iptables 通讯端口转接(Port Forwarding)

    是一种特殊的DNAT操作,其作用是让一部电脑(通常是防火牆)担任其它电脑的代理伺服器(proxy).防火牆接收外界网络接传给它自己的包,然后改写包的目的地位址或目的端口,使其像是要送到內部网路其它电脑 ...

  6. Scrapy五大核心组件简介

    五大核心组件 scrapy框架主要由五大组件组成,他们分别是调度器(Scheduler),下载器(Downloader),爬虫(Spider),和实体管道(Item Pipeline),Scrapy引 ...

  7. 禁用gpu首选

    import osos.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"os.environ["CUDA_VIS ...

  8. windows/Linux/Mac下安装maven,maven作用

    Linux下安装maven 1.首先到Maven官网下载安装文件,目前最新版本为3.0.3,下载文件为apache-maven-3.3.9-bin.tar.gz,下载可以使用wget命令: 2.进入下 ...

  9. Linux 端口进程查看

    netstat -lnp|grep 80

  10. 央行下属的上海资信网络金融征信系统(NFCS)签约机构数量突破800家

    央行下属的上海资信网络金融征信系统(NFCS)签约机构数量突破800家 ——已接入NFCS的P2P网贷机构将优先 接入央行征信系统   P2P网贷行业的健康发展依赖于信用体系的支撑和保障,加快完善适应 ...