BZOJ4241 历史研究 (分块 回滚莫队-教程向)
来源:互联网 发布:opencv python视频教程 编辑:程序博客网 时间:2024/05/07 03:45
题目大意
给定一个长度为
题解
看见这种xjb询问的题当然是要下意识地用分块来搞一搞的,又因为只有询问,且题目没有要求强制在线,所以就可以理所应当地“分块+莫队”来搞这道题了。
对于这道题,莫队的加入操作是很好实现的,只要增加一下被加入区间的权值的出现次数并同时更新一下答案就可以了,但是删除操作却很难实现,因为删除操作后无法O(1)地更新答案。这时一位id为alone_wolf的神犇为我提供了一个思路:实现没有删除操作,只有加入操作的回滚式莫队算法。
回滚式莫队是以询问的左端点所在的块为第一关键字,右端点为第二关键字对询问进行排序的。考虑枚举每一个块,枚举这个块时处理左端点在这个块内的所有询问。因为对于左端点在相同块内的询问,其右端点一定是递增的(因为就是这么排序的)。
对于询问的右端点和左端点在同一块内的,询问的大小一定小于
对于其余的询问,因为右端点是单调向右的,所以不会出现左右摆动的情况,因此对于当前块右端点右边的部分只要单调地加入就可以了,因为只会单调地加入元素,所以这部分的总时间复杂度为
时间复杂度
代码
/************************************************************** Problem: 4241 User: CHN Language: C++ Result: Accepted Time:9968 ms Memory:5592 kb****************************************************************/#include <cstdio>#include <iostream>#include <algorithm>using namespace std;inline int read() { register int val=0; char ch; while(~(ch=getchar()) && (ch<'0' || ch>'9')); val=ch-'0'; while(~(ch=getchar()) && (ch>='0' && ch<='9')) val=(val<<1)+(val<<3)+ch-'0'; return val;}const int maxn=int(1e5)+111;int n,m;int a[maxn], b[maxn], v[maxn];int siz, num, bel[maxn];long long ans[maxn];struct Q { int l,r,id; bool operator < (const Q &b) const { return bel[l]==bel[b.l]?r<b.r:bel[l]<bel[b.l]; }}q[maxn];void Read() { register int i; n=read(), m=read(); for(i=1;i<=n;++i) v[i]=a[i]=read(); sort(v+1,v+1+n); int nn=unique(v+1,v+1+n)-(v+1); for(i=1;i<=n;++i) b[i]=lower_bound(v+1,v+1+nn,a[i])-v; for(i=1;i<=m;++i) { q[i].l=read(), q[i].r=read(); q[i].id=i; } while(siz*siz<n) ++siz; for(i=1;i<=n;++i) bel[i]=(i-1)/siz+1, num=max(num,bel[i]); sort(q+1,q+1+m); return;}long long tmp=0;int cnt[maxn];void Add(int id) { ++cnt[b[id]]; tmp=max(tmp,1ll*cnt[b[id]]*a[id]);}void Del(int id) { --cnt[b[id]];}long long small(int l,int r) { static int cnt2[maxn]; long long res=0; register int i; for(i=l;i<=r;++i) cnt2[b[i]]=0; for(i=l;i<=r;++i) { ++cnt2[b[i]]; res=max(res,1ll*cnt2[b[i]]*a[i]); } return res;}int Mo(int pos,int id) { int L=min(id*siz,n); register int i=pos,j, ql=L+1, qr=ql-1; for(j=1;j<=n;++j) cnt[j]=0; tmp=0; for(;bel[q[i].l]==id;++i) { if(bel[q[i].l]==bel[q[i].r]) { ans[q[i].id]=small(q[i].l,q[i].r); continue; } while(qr<q[i].r) Add(++qr); long long cur=tmp; while(ql>q[i].l) Add(--ql); ans[q[i].id]=tmp; while(ql<L+1) Del(ql++); tmp=cur; } return i;}void Solve() { register int i,pos=1; for(i=1;i<=num;++i) pos=Mo(pos,i); return;}int main() {#ifndef ONLINE_JUDGE freopen("input.txt","r",stdin);// freopen("output.txt","w",stdout);#endif Read(); Solve(); for(int i=1;i<=m;++i) printf("%lld\n",ans[i]); return 0;}
阅读全文
1 0
- BZOJ4241 历史研究 (分块 回滚莫队-教程向)
- 【bzoj4241】历史研究 分块
- bzoj4241 历史研究 (回滚莫队)
- bzoj4241 历史研究 回滚莫队
- [bzoj4241]历史研究 回滚莫队
- [BZOJ4241]-历史研究-回滚莫队
- 【BZOJ4241】【回滚莫队】历史研究 (非题解的学习分析)
- 【bzoj4241】历史研究
- [bzoj4241]历史研究
- BZOJ4241 历史研究
- 【bzoj4241】 历史研究
- bzoj4241: 历史研究
- 【bzoj4241】历史研究
- Bzoj4241:历史研究:莫队算法
- BZOJ4241 历史研究 莫队算法 堆
- bzoj 4241: 历史研究 分块
- [分块] BZOJ 4241 历史研究
- BZOJ 4241 历史研究 (回滚莫队)
- head first 设计模式 Observer模式
- filter、map、reduce学习
- Oracle第二、三章 限制数据查询
- poj 1218 THE DRUNK JAILER
- C数据结构设计中,表首结点和二叉树根结点的头指针——传指针还是传指针的指针?
- BZOJ4241 历史研究 (分块 回滚莫队-教程向)
- java继承
- C++11 std::unique_lock与std::lock_guard区别及多线程应用实例
- vim手册
- Flume的安装部署
- 日收益率和累计收益
- Android缓存处理
- C++多态性
- 【LeetCode】5. Longest Palindromic Substring