CF_85D
这个题目可以用sum[cur][i]表示第cur个节点所辖区间的下标模5为i的整数之和,这样只要再加一个表示节点所辖区间的整数数目的标记num[cur],每次就可以方便的计算出sum[cur][i]的值了
#include<stdio.h> #include<string.h> #include<stdlib.h> #define MAXD 100010 struct Question { char b[5]; int x; }question[MAXD]; int N, num[4 * MAXD], tx[MAXD], X; long long int sum[4 * MAXD][5]; int cmp(const void *_p, const void *_q) { int *p = (int *)_p, *q = (int *)_q; return *p < *q ? -1 : 1; } void build(int cur, int x, int y) { int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1; memset(sum[cur], 0, sizeof(sum[cur])); num[cur] = 0; if(x == y) return ; build(ls, x, mid); build(rs, mid + 1, y); } void init() { int i, j, k; for(i = k = 0; i < N; i ++) { scanf("%s", question[i].b); if(question[i].b[0] == 'a' || question[i].b[0] == 'd') { scanf("%d", &question[i].x); tx[k ++] = question[i].x; } } qsort(tx, k, sizeof(tx[0]), cmp); X = 0; for(i = 0; i < k; i ++) if(i == 0 || tx[i] != tx[i - 1]) tx[X ++] = tx[i]; if(X) build(1, 0, X - 1); } int BS(int x) { int mid, min = 0, max = X; for(;;) { mid = (min + max) >> 1; if(mid == min) break; if(tx[mid] <= x) min = mid; else max = mid; } return mid; } void update(int cur) { int i, ls = cur << 1, rs = (cur << 1) | 1; num[cur] = num[ls] + num[rs]; for(i = 0; i < 5; i ++) sum[cur][i] = sum[ls][i] + sum[rs][(i + 5 - num[ls] % 5) % 5]; } void refresh(int cur, int x, int y, int k, int c) { int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1; if(x == y) { if(c) num[cur] = 1, sum[cur][0] = tx[k]; else num[cur] = 0, sum[cur][0] = 0; return ; } if(k <= mid) refresh(ls, x, mid, k, c); else refresh(rs, mid + 1, y, k, c); update(cur); } void ADD(int x) { int k = BS(x); refresh(1, 0, X - 1, k, 1); } void Del(int x) { int k = BS(x); refresh(1, 0, X - 1, k, 0); } void solve() { int i, j, k; for(i = 0; i < N; i ++) { if(question[i].b[0] == 'a') ADD(question[i].x); else if(question[i].b[0] == 'd') Del(question[i].x); else printf("%I64d\n", sum[1][2]); } } int main() { while(scanf("%d", &N) == 1) { init(); solve(); } return 0; }