回滚莫队 刷题记录
BZOJ4241: 历史研究
给一个长为n的数组,q次查询,查询l~r区间内某个数的值乘以该数出现的次数的最大值。
明显添加比较容易删除比较难,所以回滚莫队
先离散化数,然后在莫队的时候维护桶。
所谓回滚莫队就是lefl每次都到块的最右边这样就不会有删除操作了。
1 #include <bits/stdc++.h> 2 #define nmax 100010 3 #define f1n for(int i=1; i<=n; i++) 4 5 using namespace std; 6 typedef long long ll; 7 int n, q, nb, cb; 8 ll pa[nmax], cnt[nmax], fi[nmax]; 9 int c[nmax]; 10 int pos[nmax]; 11 struct ques{ 12 int l, r, pl, id; 13 bool operator < (const ques myc) const { 14 return (myc.pl==pl) ? (myc.r>r) : (myc.pl>pl) ; 15 } //---------- 16 }qe[nmax]; 17 struct mylsh{ 18 ll x; 19 int id; 20 bool operator < (const mylsh myc) const { return myc.x > x; } 21 }lsh[nmax]; 22 23 void build(){ 24 scanf("%d%d", &n, &q); 25 nb = (int)sqrt(n); 26 f1n { 27 scanf("%lld", &lsh[i].x); 28 lsh[i].id = i; 29 } 30 sort(lsh+1, lsh+1+n); 31 int j=0; 32 lsh[0].x = lsh[1].x+1; 33 f1n{ 34 if(lsh[i].x != lsh[i-1].x) j++; 35 c[ lsh[i].id ] = j; 36 fi[j] = lsh[i].x; 37 } 38 f1n pos[i] = (i-1)/nb+1; //-------- 39 for (int i=1; i<=q; i++) { 40 scanf("%d%d", &qe[i].l, &qe[i].r); 41 qe[i].id = i; 42 qe[i].pl = pos[ qe[i].l ]; 43 } 44 sort(qe+1, qe+1+q); 45 } 46 47 inline void upd(int p, ll& ta){ 48 cnt[ c[p] ]++; 49 ta = max( ta, cnt[ c[p] ]*fi[ c[p] ] ); 50 } 51 52 inline void init(){ memset(cnt,0,sizeof(cnt)); } 53 54 inline ll myf(int l, int r){ 55 ll ans=0; 56 for (int i=l; i<=r; i++) { 57 cnt[ c[i] ]++; 58 ans = max(ans, cnt[ c[i] ] * fi[ c[i] ] ); 59 } 60 for (int i=l; i<=r; i++) cnt[ c[i] ]--; 61 return ans; 62 } 63 64 int main(){ 65 //freopen("owo.in","r",stdin); 66 build(); 67 int tr, tmp; 68 ll ta; 69 qe[0].pl=-1; 70 for (int i=1; i<=q; i++) { 71 if( qe[i].pl != qe[i-1].pl ) { 72 init(); 73 tmp = qe[i].pl*nb; 74 tr = tmp; 75 ta = 0; 76 } 77 if( pos[ qe[i].r ] == qe[i].pl ) pa[ qe[i].id ] = myf(qe[i].l, qe[i].r); 78 else{ 79 while(qe[i].r>tr) { tr++; upd(tr, ta); } 80 ll jl = ta; 81 for (int k = tmp; k>=qe[i].l; k--) upd(k, ta); 82 pa[ qe[i].id ] = ta; 83 for (int k = tmp; k>=qe[i].l; k--) cnt[ c[k] ]--; //撤销影响 84 ta = jl; 85 } 86 } 87 for (int i=1; i<=q; i++) printf("%lld\n", pa[i]); 88 return 0; 89 }