线段树好题,和 15 年的广东省省赛 C 题有相似之处,一开始我的思路有偏差,看了别人的博客后感觉处处技巧都是精华,主要是区间合并的技巧一时很难想到,先附上代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define root int rt, int l, int r 6 #define lson rt << 1, l, mid 7 #define rson rt << 1 | 1, mid + 1, r 8 #define makemid int mid = l + r >> 1 9 typedef long long LL; 10 const int N = 100005; 11 12 int cnt[N << 2]; 13 LL sum[N << 2][5]; 14 15 void build(root) { 16 cnt[rt] = 0; 17 for(int i = 0; i < 5; ++i) 18 sum[rt][i] = 0; 19 if(l == r) return ; 20 makemid; 21 build(lson); 22 build(rson); 23 } 24 25 inline int mymod(int x, int mod) { 26 if(x < 0) return (x % mod + mod) % mod; 27 return x % mod; 28 } 29 30 inline void pushup(int rt) { 31 for(int i = 0; i < 5; ++i) 32 sum[rt][i] = sum[rt << 1][i] + sum[rt << 1 | 1][mymod(i - cnt[rt << 1], 5)]; 33 } 34 35 bool flag; 36 int pos, val; 37 38 void update(root) { 39 flag ? ++cnt[rt] : --cnt[rt]; 40 if(l == r) { 41 sum[rt][1] = flag ? val: 0; 42 return ; 43 } 44 makemid; 45 if(pos <= mid) update(lson); 46 else update(rson); 47 pushup(rt); 48 } 49 50 int find(int *c, int low, int up, int x) { 51 int mid; 52 while(low <= up) { 53 mid = low + up >> 1; 54 if(x == c[mid]) return mid; 55 else if(x < c[mid]) up = mid - 1; 56 else low = mid + 1; 57 } 58 return low; 59 } 60 61 char op[N][5]; 62 int c[N], digit[N]; 63 64 int main() { 65 int n,k; 66 while(~scanf("%d",&n)) { 67 k = 0; 68 for(int i = 0; i < n; ++i) { 69 scanf("%s",op[i]); 70 if(op[i][0] != 's') { 71 scanf("%d", c + i); 72 digit[k++] = c[i]; 73 } 74 } 75 sort(digit, digit + k); 76 int len = unique(digit, digit + k) - digit; 77 78 if(len) build(1,1,len); 79 80 for(int i = 0; i < n; ++i) { 81 if(op[i][0] == 's') printf("%I64d ",sum[1][3]); 82 else { 83 flag = op[i][0] == 'a'; 84 pos = find(digit, 0, len - 1, c[i]) + 1; 85 val = c[i]; 86 update(1,1,len); 87 } 88 } 89 } 90 return 0; 91 }
做 100 道水题,不如做一道难题来得更有意义。