题面
解析
今天Doggu讲了根号类算法,这道题使用的就是其中之一的回滚莫队。
这道题显然支持离线操作,询问区间,立即联想到莫队,对于区间扩大的信息更新是很容易的,但要区间缩小,信息的更新就很难了,于是就有一个叫做回滚莫队的东西。思路大体与莫队一致,只是对于块内询问每一次都暴力解决, 对于跨越块的询问,固定左指针在块的右端点+1的位置,先延伸右指针, 记录此时的答案now, 再延伸左指针,统计答案,然后左指针撤回到所在块的右端点+1的位置,同时将之前记录的答案now赋给现在的答案,这个操作叫做回滚。
还有要注意常数优化,我之前的写法写挂了无数次。
代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 100005; template<class T> inline void read(T &re) { re=0; T sign=1; char tmp; while((tmp=getchar())&&(tmp<'0'||tmp>'9')) if(tmp=='-') sign=-1; re=tmp-'0'; while((tmp=getchar())&&(tmp>='0'&&tmp<='9')) re=(re<<3)+(re<<1)+(tmp-'0'); re*=sign; } int n, Q, siz, pos[maxn], a[maxn], b[maxn], tot, t[maxn]; ll ans[maxn]; struct question{ int l, r, num; }q[maxn]; inline bool cmp(question x, question y) { if(pos[x.l] == pos[y.l]) return x.r < y.r; return pos[x.l] < pos[y.l]; } inline void work() { register int las = 0, L, R; register ll res = 0; for(register int i = 1; i <= Q; ++i) { if(pos[q[i].l] != las) { for(register int j = 1; j <= tot; ++j) t[j] = 0; res = 0; L = min(siz * pos[q[i].l], n) + 1; R = L - 1; } if(pos[q[i].l] == pos[q[i].r]) { for(register int j = q[i].l; j <= q[i].r; ++j) { t[a[j]] ++; res = max(res, 1LL * b[a[j]] * t[a[j]]); } for(int j = q[i].l; j <= q[i].r; ++j) t[a[j]] --; ans[q[i].num] = res; res = 0; las = pos[q[i].l]; } else { while(R < q[i].r) { R++; t[a[R]]++; res = max(res, 1LL * b[a[R]] * t[a[R]]); } ll now = res; register int ql = L; while(q[i].l < L) { L --; t[a[L]] ++; res = max(res, 1LL * b[a[L]] * t[a[L]]); } ans[q[i].num] = res; while(L < ql) t[a[L++]] --; res = now; las = pos[q[i].l]; } } } int main() { read(n);read(Q); siz = (int)sqrt(n * 1.0 + 0.5); for(register int i = 1; i <= n; ++i) read(a[i]), b[i] = a[i]; sort(b + 1, b + n + 1); tot = unique(b + 1, b + n + 1) - b - 1; for(register int i = 1; i <= n; ++i) { a[i] = lower_bound(b + 1, b + tot + 1, a[i]) - b; pos[i] = (i - 1) / siz + 1; } for(register int i = 1; i <= Q; ++i) { read(q[i].l);read(q[i].r); q[i].num = i; } sort(q + 1, q + Q + 1, cmp); work(); for(int i = 1 ; i <= Q; ++i) printf("%lld\n", ans[i]); return 0; }