有一个多重集合S(即里面元素可以有重复),初始状态下有n个元素,对他进行如下操作:
1、向S里面添加一个值为v的元素。输入格式为1v
2、向S里面删除一个值为v的元素。输入格式为2v
3、询问S里面的元素两两之差绝对值之和。输入格式为3
对于样例,
操作3,|1-2|+|1-3|+|2-3|=4
操作1 4之后,集合中的数字为1 2 3 4
操作3,|1-2|+|1-3|+|2-3|+|1-4|+|2-4|+|3-4|=10
操作2 2之后,集合中的数字为1 3 4
操作3,|1-3|+|1-4|+|3-4|=6
Input
第一行输入两个整数n,Q表示集合中初始元素个数和操作次数。(1<=n,Q<=100,000)
第二行给出n个整数a[0],a[1],a[2],…,a[n-1],表示初始集合中的元素。(0<=a[i]<=1,000,000,000)
接下来Q行,每行一个操作。(0<=v<=1,000,000,000)
Output
对于第2类操作,如果集合中不存在值为v的元素可供删除,输出-1。
对于第3类操作,输出答案。
Input示例
3 5
1 2 3
3
1 4
3
2 2
3
Output示例
4
10
6
思路:
对于递增的n个数a[1],a[2]...a[n],如果已经计算出1至n-1的差和,这时a[n]贡献的差和为(a[n] - a[1]) + (a[n] - a[2]) + ... + (a[n] - a[n-1]) = (n-1) * a[n] - (a[1] + a[2] + ... + a[n-1])。因此这又是一个求前缀和的问题,用树状数组来解决。
在本题中,增加一个数t[i]后的结果变更为:result = result + (t[i] * (ansn * 2 - sumn) - 2 * anss + sum);
(t[i] * (ansn * 2 - sumn) - 2 * anss + sum)是考虑导t[i]对它之前的差和贡献和对它之后的差和贡献。
将所有出现的数(包括后来增加的数)排序。分别用两个数组统计增减一个数后,该数之前的和以及该数之前的数量。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 10;
struct node
{
int id;
ll v;
}q[MAXN];
ll a[MAXN*4];
int b[MAXN*4];
ll t[MAXN];
ll cur[MAXN];
int num[MAXN];
ll low(int k)
{
return k & (-k);
}
void update(int k, ll v, int v2)
{
while (k < MAXN)
{
a[k] += v;
b[k] += v2;
k += low(k);
}
}
ll anss, ansn;
ll sums(int k)
{
anss = 0;
ansn = 0;
while (k > 0)
{
anss += a[k];
ansn += b[k];
k -= low(k);
}
}
int main()
{
int n, Q;
cin >> n >> Q;
for (int i = 0; i < n; i++)
{
cin >> t[i];
cur[i] = t[i];
}
int cnt = n;
for (int i = 0; i < Q; i++)
{
cin >> q[i].id;
if (q[i].id != 3)
{
cin >> q[i].v;
cur[cnt] = q[i].v;
cnt++;
}
}
sort(cur, cur + cnt);
int all = unique(cur, cur + cnt) - cur;
ll sum = 0;
ll result = 0;
int sumn = 0;
int temp;
for (int i = 0; i < n; i++)
{
temp = lower_bound(cur, cur + all, t[i]) - cur + 1;
num[temp]++;
sumn++;
update(temp, t[i], 1);
sum += t[i];
sums(temp);
result = result + (t[i] * (ansn * 2 - sumn) - 2 * anss + sum);
}
ll cwt;
for (int i = 0; i < Q; i++)
{
if (q[i].id == 1)
{
temp = lower_bound(cur,cur+all, q[i].v) - cur + 1;
update(temp, q[i].v, 1);
num[temp]++;
sum += q[i].v;
sumn++;
sums(temp);
result = result + (q[i].v * (ansn * 2 - sumn) - 2 * anss + sum);
}
else if (q[i].id == 2)
{
temp = lower_bound(cur, cur+all, q[i].v) - cur + 1;
if (num[temp] == 0)
{
cout << "-1" << endl;
}
else
{
sums(temp);
result = result - (q[i].v * (ansn * 2 - sumn) - 2 * anss + sum);
update(temp, -q[i].v, -1);
num[temp]--;
sum -= q[i].v;
sumn--;
}
}
else if (q[i].id == 3)
{
cout << result << endl;
}
}
return 0;
}