hihocoder offer收割编程练习赛11 D 排队接水

思路:

莫队算法+树状数组。

莫队算法的基本思想是对大量要查询的区间进行离线处理,按照一定的顺序计算,来降低复杂度。概括来说,我们在知道了[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 }
原文地址:https://www.cnblogs.com/wangyiming/p/6626853.html