思路:
莫队算法+树状数组。
莫队算法的基本思想是对大量要查询的区间进行离线处理,按照一定的顺序计算,来降低复杂度。概括来说,我们在知道了[l, r]的解,并且可以通过一个较低的复杂度推出[l - 1, r], [l, r - 1], [l + 1, r], [l, r + 1]的解的情况下,则可使用该算法。
对该算法比较好的介绍:
1.https://blog.sengxian.com/algorithms/mo-s-algorithm
2.http://blog.csdn.net/bossup/article/details/39236275
在本题中,对于一个区间[l, r],实际上是求a[l] * (r - l + 1) + a[l + 1] * (r - l) +... + a[r] * 1。
那么在知道了[l, r]的解的前提下,如何转移到[l', r']呢?
我们可以观察一个简单的情况:[l, r] -> [l - 1, r]。比如[1, 2, 3, 4] -> [3, 1, 2, 3, 4]。
对于这个例子,假设原来的解为res。那么在左边加上一个‘3’之后,新的解res_new为
1 * 5 + 2 * 4 + 3 * 3 + 3 * 2 + 4 * 1 =
1 * 4 + 2 * 3 + 3 * 2 + 4 * 1 + 1 + 2 + 3 * 3 =
res + 1 + 2 + 3 * 3。
实际上就是原来的解res + 原来的区间内比3小的数的和 + 3 * (原来的区间内大于等于3的数的个数 + 1);
反过来,[3, 1, 2, 3, 4] -> [1, 2, 3, 4]的过程类似。
我们可以使用两个树状数组来维护变化的部分。具体来说其中一个维护大于等于3的数的个数,另一个维护小于3的数的和即可。
实现:
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 using namespace std; 6 typedef long long ll; 7 8 const int N = 200000; 9 10 int t, n, m, L, R, a[N + 5], block; 11 ll tot = 0, ans[N + 5]; 12 ll bit1[N + 5]; //统计个数 13 ll bit2[N + 5]; //统计和 14 15 struct query 16 { 17 int l, r, id; 18 }; 19 query Q[N + 5]; 20 21 bool cmp(const query & x, const query & y) 22 { 23 if (x.l / block != y.l / block) 24 return x.l / block < y.l / block; 25 return x.r < y.r; 26 } 27 28 void bit_add(ll * bit, int i, int x) 29 { 30 if (i == 0) 31 return; 32 while (i <= N) 33 { 34 bit[i] += x; 35 i += i & -i; 36 } 37 } 38 39 ll bit_sum(ll * bit, int i) 40 { 41 ll s = 0; 42 while (i) 43 { 44 s += bit[i]; 45 i -= i & -i; 46 } 47 return s; 48 } 49 50 ll bit_query(ll * bit, int l ,int r) 51 { 52 return bit_sum(bit, r) - bit_sum(bit, l - 1); 53 } 54 55 void Add(int pos) 56 { 57 tot += (ll)a[pos] * (bit_query(bit1, a[pos], N + 1) + 1); 58 tot += bit_query(bit2, 1, a[pos] - 1); 59 bit_add(bit1, a[pos], 1); 60 bit_add(bit2, a[pos], a[pos]); 61 } 62 63 void Del(int pos) 64 { 65 tot -= (ll)a[pos] * bit_query(bit1, a[pos], N + 1); 66 tot -= bit_query(bit2, 1, a[pos] - 1); 67 bit_add(bit1, a[pos], -1); 68 bit_add(bit2, a[pos], -a[pos]); 69 } 70 71 void init() 72 { 73 block = sqrt(n); 74 L = R = 1; 75 tot = a[1]; 76 memset(bit1, 0, sizeof(bit1)); 77 memset(bit2, 0, sizeof(bit2)); 78 bit_add(bit1, a[1], 1); 79 bit_add(bit2, a[1], a[1]); 80 } 81 82 int main() 83 { 84 cin >> t; 85 while (t--) 86 { 87 cin >> n >> m; 88 for (int i = 1; i <= n; i++) 89 { 90 scanf("%d", &a[i]); 91 } 92 init(); 93 for (int i = 0; i < m; i++) 94 { 95 scanf("%d %d", &Q[i].l, &Q[i].r); 96 Q[i].id = i; 97 } 98 sort(Q, Q + m, cmp); 99 for (int i = 0; i < m; i++) 100 { 101 while (L < Q[i].l) 102 Del(L++); 103 while (L > Q[i].l) 104 Add(--L); 105 while (R < Q[i].r) 106 Add(++R); 107 while (R > Q[i].r) 108 Del(R--); 109 ans[Q[i].id] = tot; 110 } 111 for (int i = 0; i < m; i++) 112 { 113 printf("%lld ", ans[i]); 114 } 115 } 116 return 0; 117 }