题目

题目描述
In one well-known algorithm of finding the kk -th order statistics we should divide all elements into groups of five consecutive elements and find the median of each five. A median is called the middle element of a sorted array (it’s the third largest element for a group of five). To increase the algorithm’s performance speed on a modern video card, you should be able to find a sum of medians in each five of the array.

A sum of medians of a sorted kk -element set S={a_{1},a_{2},…,a_{k}}S=a
1

,a
2

,…,a
k

, where a_{1}<a_{2}<a_{3}<…<a_{k} , will be understood by as

The operator stands for taking the remainder, that is stands for the remainder of dividing xx by yy .

To organize exercise testing quickly calculating the sum of medians for a changing set was needed.

输入格式
The first line contains number nn ( 1<=n<=10^{5}1<=n<=10
5
), the number of operations performed.

Then each of nn lines contains the description of one of the three operations:

add xx — add the element xx to the set;
del xx — delete the element xx from the set;
sum — find the sum of medians of the set.
For any add xx operation it is true that the element xx is not included in the set directly before the operation.

For any del xx operation it is true that the element xx is included in the set directly before the operation.

All the numbers in the input are positive integers, not exceeding 10^{9}10
9
.

输出格式
For each operation sum print on the single line the sum of medians of the current set. If the set is empty, print 0.

Please, do not use the %lld specificator to read or write 64-bit integers in C++. It is preferred to use the cin, cout streams (also you may use the %I64d specificator).

题意翻译
一个集合,初始为空。现有三个操作:
1.add:向集合里加入数x,保证加入前集合中没有数x;
2.del:从集合中删除数x,保证删除前集合中有x;
3.sum:询问将集合里的数从小到大排序后,求下标i模5余3的数的和。
现有n次操作,对于每个查询操作,输出答案
Translated by @maojinyang

输入输出样例
输入 #1复制
6
add 4
add 5
add 1
add 2
add 3
sum
输出 #1复制
3
输入 #2复制
14
add 1
add 7
add 2
add 5
sum
add 6
add 8
add 9
add 3
add 4
add 10
sum
del 1
sum
输出 #2复制
5
11
13

思路

首先建一棵权值线段树,然后每个节点维护几个东西

cnt,即这个节点所代表的值域区间里有多少个数
s[0…4],s[i]表示这个节点内的所有数排序后下标%5=i的数的和
上面两个东西随便算算就好了

代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 1e5 + 10;

struct node {
	int lc, rc;
	ll s[5]; int cnt;
} t[N * 40];
int rt = 0, siz = 0;

void pushup(int x) {
	int lc = t[x].lc, rc = t[x].rc, ls = t[lc].cnt;
	for (int i = 0; i < 5; i++) t[x].s[i] = t[lc].s[i];
	for (int i = 0; i < 5; i++) t[x].s[(i + ls) % 5] += t[rc].s[i];
	t[x].cnt = t[lc].cnt + t[rc].cnt;
}

void ins(int &x, int l, int r, int p, int v) 
{
	if (!x) x = ++siz;
	if (l == r) {
		t[x].cnt += v;
		t[x].s[1] += 1ll * l * v;
		return;
	}
	int mid = (l + r) >> 1;
	if (p <= mid) ins(t[x].lc, l, mid, p, v);
	else ins(t[x].rc, mid + 1, r, p, v);
	pushup(x);
}

int main() {
	char s[23];
	int _; for (scanf("%d", &_); _; _--) 
	{
		scanf("%s", s);
		if (s[0] == 's') printf("%lld\n", t[rt].s[3]);
		else {
			int d = s[0] == 'd' ? -1 : 1, v;
			scanf("%d", &v);
			ins(rt, 1, 1e9, v, d);
		}
	}
	return 0;
}