BZOJ4241 历史研究(莫队)
生活随笔
收集整理的這篇文章主要介紹了
BZOJ4241 历史研究(莫队)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
如果分塊的話與區間眾數沒有本質區別。這里考慮莫隊。
顯然莫隊時的刪除可以用堆維護,但多了一個log不太跑得過。
有一種叫回滾莫隊的trick,可以將問題變為只有加入操作。按莫隊時分的塊依次處理,一塊中左端點的差不超過√n,右端點單調遞增。首先將右端點也在該塊中的詢問暴力處理。然后令指針l在下一塊開頭,指針r在這一塊結尾。暴力擴展右端點移動指針r,到達詢問點時,移動指針l以回答詢問,但不讓指針l的移動對之后的詢問產生影響,即回滾。這樣就可以處理刪除了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() {int x=0,f=1;char c=getchar();while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();return x*f; } #define N 100010 #define ll long long int n,m,a[N],b[N],cnt[N]; ll ans[N]; struct data {int x,y,k,i;bool operator <(const data&a) const{return k<a.k||k==a.k&&y<a.y;} }q[N]; int main() { #ifndef ONLINE_JUDGEfreopen("bzoj4241.in","r",stdin);freopen("bzoj4241.out","w",stdout);const char LL[]="%I64d\n"; #elseconst char LL[]="%lld\n"; #endifn=read(),m=read();for (int i=1;i<=n;i++) b[i]=a[i]=read();sort(b+1,b+n+1);int t=unique(b+1,b+n+1)-b-1;for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+t+1,a[i])-b;int block=sqrt(n);for (int i=1;i<=m;i++) q[i].x=read(),q[i].y=read(),q[i].k=q[i].x/block,q[i].i=i;sort(q+1,q+m+1);for (int i=1;i<=m;i++){int t=i;while (t<m&&q[t+1].k==q[i].k) t++;while (i<=t&&q[i].y<(q[i].k+1)*block){for (int j=q[i].x;j<=q[i].y;j++){cnt[a[j]]++;ans[q[i].i]=max(ans[q[i].i],1ll*cnt[a[j]]*b[a[j]]);}for (int j=q[i].x;j<=q[i].y;j++) cnt[a[j]]--;i++;}int r=(q[i].k+1)*block-1;ll v=0;for (int j=i;j<=t;j++){while (r<q[j].y){cnt[a[++r]]++;v=max(v,1ll*cnt[a[r]]*b[a[r]]);}ans[q[j].i]=v;for (int k=(q[i].k+1)*block-1;k>=q[j].x;k--){cnt[a[k]]++;ans[q[j].i]=max(ans[q[j].i],1ll*cnt[a[k]]*b[a[k]]);}for (int k=(q[i].k+1)*block-1;k>=q[j].x;k--) cnt[a[k]]--;}memset(cnt,0,sizeof(cnt));i=t;}for (int i=1;i<=m;i++) printf(LL,ans[i]);return 0; }?
轉載于:https://www.cnblogs.com/Gloid/p/9833040.html
總結
以上是生活随笔為你收集整理的BZOJ4241 历史研究(莫队)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 作业 20181016-10 每周例行报
- 下一篇: python3 deque(双向队列)