【题解】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. auto uninstaller密钥激活码破解注册机ver 8.8.58

    auto uninstaller密钥破解注册机ver 8.8.58 楼主分享几个auto uninstaller密钥破解注册机,可以用于auto uninstaller 8.8.58 .因为每个版本的 ...

  2. win10 uwp httpClient 登陆CSDN

    本文告诉大家如何模拟登陆csdn,这个方法可以用于模拟登陆其他网站. HttpClient 使用 Cookie 我们可以使用下面代码让 HttpClient 使用 Cookie ,有了这个才可以保存登 ...

  3. POJ3080 Blue Jeans 题解 KMP算法

    题目链接:http://poj.org/problem?id=3080 题目大意:给你N个长度为60的字符串(N<=10),求他们的最长公共子串(长度>=3). 题目分析:KMP字符串匹配 ...

  4. hdu 3339 In Action(迪杰斯特拉+01背包)

    In Action Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  5. H3C ISDN功能组和参考点

  6. [转][ASP.NET Core 3框架揭秘] 跨平台开发体验: Windows [中篇]

    我们在<上篇>利用dotnet new命令创建了一个简单的控制台程序,接下来我们将它改造成一个ASP.NET Core应用.一个ASP.NET Core应用构建在ASP.NET Core框 ...

  7. HDU 1026 BSF+优先队列+记录路径、

    #include<iostream> #include<cmath> #include<cstring> #include<cstdio> #inclu ...

  8. 最全Pycharm教程(43)——Pycharm扩展功能之UML类图使用 代码结构

    版权声明:本文为博主原创文章,转载时麻烦注明源文章链接,谢谢合作 https://blog.csdn.net/u013088062/article/details/50353202 1.什么是UML ...

  9. H3C 高级ACL部署位置示例

  10. C# “不支持给定路径的格式”异常处理

    问题背景 无聊研究了一下怎么发送邮件(包含附件),但发现附带的文件路径除了报错就是报错,不知道为什么. 用了不下好几种方式,比如 var x = "E:\\Git\\cmd\\git.exe ...