从零开始的莫队
本篇主要是我学习了莫队算法之后的一些感受,仅包含普通莫队与普通带修改莫队相关知识,望各位大佬指点一二
首先就是非常经典的莫队适用的题型:[ L 1 , R 1 ] [L_1,R_1] [ L 1  , R 1  ] O ( ∣ L 1 − L 2 ∣ ) O(|L_1 - L_2|) O ( ∣ L 1  − L 2  ∣ ) L 2 L_2 L 2  O ( ∣ R 1 − R 2 ∣ ) O(|R_1 - R_2|) O ( ∣ R 1  − R 2  ∣ ) R 2 R_2 R 2  [ L 2 , R 2 ] [L_2,R_2] [ L 2  , R 2  ] 1 1 1 O ( 1 ) O(1) O ( 1 ) 
下面就来说一下莫队的基本思想:O ( 1 ) O(1) O ( 1 ) [ 0 , 0 ] [0,0] [ 0 , 0 ] n \sqrt n n  n 2 3 n^{\frac{2}{3}} n 3 2  n 3 4 n^{\frac{3}{4}} n 4 3  
看思想肯定是啥都不会的,下面就通过一道题具体来看一下什么是莫队(相信我莫队真的不难)
我们在本题中维护数组 t m p [ i ] tmp[i] t m p [ i ] i i i t m p [ i ] tmp[i] t m p [ i ] i i i 1 1 1 t m p [ i ] tmp[i] t m p [ i ] i i i 0 0 0 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include <bits/stdc++.h>  using  namespace  std;const  int  MAXN = 5e4 +5 ;const  int  MAXM = 2e5 +5 ;const  int  MAX_VAL = 1e6 +5 ;struct  node {	int  l,r,pos,id; }q[MAXM]; int  a[MAXN],ans[MAXM],tmp[MAX_VAL],n,S,m,res;int  bl (int  x) 	return  (x - 1 ) / S + 1 ; } bool  cmp (node l,node r) 	if (bl (l.l) != bl (r.l)) 		return  bl (l.l) < bl (r.l); 	return  l.r < r.r; } void  Dele (int  val) 	if ((--tmp[val]) == 0 ) 		res--; } void  Add (int  val) 	if ((++tmp[val]) == 1 ) 		res++; } int  main () 	cin>>n; 	S = sqrt (n); 	for (int  i=1 ; i<=n; i++){ 		cin>>a[i]; 	} 	cin>>m; 	for (int  i=1 ; i<=m; i++){ 		cin>>q[i].l>>q[i].r; 		q[i].pos = i; 	} 	sort (q+1 ,q+m+1 ,cmp);    	int  now_l = 0 ,now_r = 0 ; 	for (int  i=1 ; i<=m; i++){ 		while (now_l > q[i].l)	Add (a[--now_l]);	 		while (now_r < q[i].r)	Add (a[++now_r]); 		while (now_l < q[i].l)	Dele (a[now_l++]);    		while (now_r > q[i].r)	Dele (a[now_r--]); 		ans[q[i].pos] = res; 	} 	for (int  i=1 ; i<=m; i++){ 		cout<<ans[i]<<endl; 	} 	return  0 ; } 
b l ( i ) bl(i) b l ( i ) i i i A d d Add A d d D e l e Dele D e l e l − − l-- l − − r + + r++ r + + l + + l++ l + + r − − r-- r − − [ 5 , 3 ] [5,3] [ 5 , 3 ] 
带修改莫队与普通莫队基本是一致的,推荐理解了普通莫队之后再进行观看。
使用带修莫队,与普通莫队一样维护一个 t m p tmp t m p t m p [ i ] tmp[i] t m p [ i ] i i i 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 #include <bits/stdc++.h>  using  namespace  std;const  int  MAXN = 1e4 +5 ;const  int  MAXM = 1e4 +5 ;const  int  MAX_VAL = 1e6 +5 ;struct  node {	int  l,r,time,id; }q[MAXM]; struct  node2 {	int  pos,val; }c[MAXM]; int  tmp[MAX_VAL],a[MAXN],ans[MAXM],n,m,qnum,tim,S,res;int  bl (int  x) 	return  (x - 1 ) / S + 1 ; } bool  cmp (node x,node y) 	if (bl (x.l) != bl (y.l)) 		return  bl (x.l) < bl (y.l); 	if (bl (x.r) != bl (y.r)) 		return  bl (x.r) < bl (y.r); 	if (x.time != y.time) 		return  x.time < y.time; } void  add (int  x) 	if ((++tmp[a[x]]) == 1 ) 		res++; }  void  Dele (int  x) 	if ((--tmp[a[x]]) == 0 ) 		res--; } void  change (int  now,int  i) 	if (c[now].pos >= q[i].l && c[now].pos <= q[i].r){ 		if ((++tmp[c[now].val]) == 1 ) 			res++; 		if ((--tmp[a[c[now].pos]]) == 0 ) 			res--; 	} 	swap (c[now].val,a[c[now].pos]); } int  main () 	cin>>n>>m; 	S = int (pow (n,0.66 )); 	for (int  i=1 ; i<=n; i++){ 		cin>>a[i]; 	} 	for (int  i=1 ; i<=m; i++){ 		char  opt; 		int  x,y; 		cin>>opt>>x>>y; 		if (opt == 'Q' ){ 			q[++qnum].l = x; 			q[qnum].r = y; 			q[qnum].time = tim; 			q[qnum].id = qnum; 		} 		else  if (opt == 'R' ){ 			c[++tim].pos = x; 			c[tim].val = y; 		} 	} 	sort (q+1 ,q+qnum+1 ,cmp); 	int  now = 0 ,now_l = 0 ,now_r = 0 ; 	for (int  i=1 ; i<=qnum; i++){ 		while (q[i].l < now_l)	add (--now_l); 		while (q[i].r > now_r)	add (++now_r); 		while (q[i].l > now_l)	Dele (now_l++); 		while (q[i].r < now_r)	Dele (now_r--); 		while (q[i].time < now)	change (now--,i);   		while (q[i].time > now)	change (++now,i);   		ans[q[i].id] = res; 	} 	for (int  i=1 ; i<=qnum; i++){ 		cout<<ans[i]<<endl; 	} 	return  0 ; } 
其他的我就不多说了,我们仔细读读代码就明白了,关于 c h a n g e change c h a n g e s w a p swap s w a p a a a c c c a a a c c c