回滚莫队学习笔记

回滚莫队,用来处理增加好维护,删除不好维护的情况

  • 参考自:oiwiki回滚莫队
  • 算法流程:考虑按值域分块,对每个询问\([l,r]\),以\(l\)所在的块为第一关键字,\(r\)为第二关键字排序
  • \([l,r]\)在同一块内,暴力即可
  • 否则\(:\)
  • 若上一个询问\(l\),所在的块和这个不同,暴力的重构即可,这个过程最多只有\(O(\sqrt n)\)次,每次最多\(O(n)\),所以\(O(n \sqrt n)\)
  • 否则我们将\(l,r\)暴力拓展,回答询问,并在回答询问后将\(l\)回滚到其所在的块的最右段\(+1\),那么撤销和拓展的时间复杂度都是\(O(\sqrt n)\),\(m\)次询问,总共就是\(O(m \sqrt n)\)
  • 所以总时间复杂度就是\(O(n \sqrt n + m \sqrt n)\)

例题:AT1219 歴史の研究

  • 模板题没什么好说的
  • 代码还是挺好写的
/*AT1219 歴史の研究*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int read(){
	char c = getchar();
	int x = 0;
	while(c < '0' || c > '9')		c = getchar();
	while(c >= '0' && c <= '9')		x = x * 10 + c - 48,c = getchar();
	return x;
}
const int _ =  2e5 + 7;
int b[_],L[_],R[_];
struct Query{
	int l,r,id;
	bool operator < (const Query &A)const{
		if(b[l] == b[A.l])	return r < A.r;
		return b[l] < b[A.l];
	}
}Q[_];
ll ans[_];int a[_],tmp[_],rk[_];
int cnt[_];
int n,m;
int main(){
	n = read(),m = read();
	for(int i = 1; i <= n; ++i)		tmp[i] = read(),a[i] = tmp[i];
	sort(tmp+1,tmp+n+1) ;
	int k = unique(tmp + 1,tmp + n + 1) - tmp - 1;
	for(int i = 1; i <= n; ++i)		rk[i] = lower_bound(tmp + 1,tmp + k + 1,a[i]) - tmp;
	int t = sqrt(n);
	for(int i = 1; i <= t; ++i){
		L[i] = R[i-1] + 1;
		R[i] = L[i] + t - 1; 
	}
	if(R[t] != n){
		t++;L[t] = R[t-1] + 1;R[t] = n;
	}
	for(int i = 1; i <= t; ++i)
		for(int j = L[i]; j <= R[i]; ++j)	b[j] = i;
	for(int i = 1; i <= m; ++i){
		Q[i].l = read(),Q[i].r = read();
		Q[i].id = i;
	}
	sort(Q+1,Q+m+1);memset(tmp,0,sizeof(tmp));
	int tp = 1;
	for(int i = 1; i <= t; ++i){
		int l = R[i],r = R[i] + 1;
		memset(cnt,0,sizeof(int) * (k + 1));
		ll v = 0;
		while(b[Q[tp].l] == i && tp <= m){
			int ql = Q[tp].l,qr = Q[tp].r;
			if(b[ql] == b[qr]){
				ll ret = 0;
				for(int j = ql; j <= qr; ++j){
					tmp[rk[j]]++;
					ret = max(ret,1ll * tmp[rk[j]] * a[j]);
				}
				ans[Q[tp].id] = ret;
				for(int j = ql; j <= qr; ++j)	tmp[rk[j]] = 0;
			}
			else{
				while(r <= qr){
					cnt[rk[r]]++;
					v = max(v,1ll * cnt[rk[r]] * a[r]);
					r++;
				}
				ll ret = 0;
				l = R[i];
				while(l >= ql){
					cnt[rk[l]]++;
					ret = max(ret,1ll * cnt[rk[l]] * a[l]);
					l--;
				}				
				ans[Q[tp].id] = max(ret,v);
				for(int j = ql; j <= R[i]; ++j)		cnt[rk[j]]--;
			}
			tp++;
		}
	}
	for(int i = 1; i <= m; ++i)		printf("%lld\n",ans[i]);
	return 0;
}
posted @ 2021-04-01 10:59  y_dove  阅读(121)  评论(0编辑  收藏  举报