Problem Description
There's a queue obeying the first in first out rule. Each time you can either push a number into the queue (+i), or pop a number out from the queue (-i). After a series of operation, you get a sequence (e.g. +1 -1 +2 +4 -2 -4). We call this sequence a queue sequence.
Now you are given a queue sequence and asked to perform several operations:
1. insert p
First you should find the smallest positive number (e.g. i) that does not appear in the current queue sequence, then you are asked to insert the +i at position p (position starts from 0). For -i, insert it into the right most position that result in a valid queue sequence (i.e. when encountered with element -x, the front of the queue should be exactly x).
For example, (+1 -1 +3 +4 -3 -4) would become (+1 +2 -1 +3 +4 -2 -3 -4) after operation 'insert 1'.
2. remove i
Remove +i and -i from the sequence.
For example, (+1 +2 -1 +3 +4 -2 -3 -4) would become (+1 +2 -1 +4 -2 -4) after operation 'remove 3'.
3. query i
Output the sum of elements between +i and -i. For example, the result of query 1, query 2, query 4 in sequence (+1 +2 -1 +4 -2 -4) is 2, 3(obtained by -1 + 4), -2 correspond.
Now you are given a queue sequence and asked to perform several operations:
1. insert p
First you should find the smallest positive number (e.g. i) that does not appear in the current queue sequence, then you are asked to insert the +i at position p (position starts from 0). For -i, insert it into the right most position that result in a valid queue sequence (i.e. when encountered with element -x, the front of the queue should be exactly x).
For example, (+1 -1 +3 +4 -3 -4) would become (+1 +2 -1 +3 +4 -2 -3 -4) after operation 'insert 1'.
2. remove i
Remove +i and -i from the sequence.
For example, (+1 +2 -1 +3 +4 -2 -3 -4) would become (+1 +2 -1 +4 -2 -4) after operation 'remove 3'.
3. query i
Output the sum of elements between +i and -i. For example, the result of query 1, query 2, query 4 in sequence (+1 +2 -1 +4 -2 -4) is 2, 3(obtained by -1 + 4), -2 correspond.
Input
There are less than 25 test cases. Each case begins with a number indicating the number of operations n (1 ≤ n ≤ 100000). The following n lines with be 'insert p', 'remove i' or 'query i'(0 ≤ p ≤ length (current sequence), 1 ≤ i, i is granted to be in the sequence).
In each case, the sequence is empty initially.
The input is terminated by EOF.
In each case, the sequence is empty initially.
The input is terminated by EOF.
Output
Before each case, print a line "Case #d:" indicating the id of the test case.
After each operation, output the sum of elements between +i and -i.
After each operation, output the sum of elements between +i and -i.
题目大意:这题太难描述了不讲了,亏出题人能想出这么难讲的题……
思路:对于插入最小正数,有一个优先队列维护即可(咋这么多人喜欢用线段树……)
然后序列用一个平衡树维护,我选择了treap,每个结点的右儿子在序列的左边,右结点在序列的右边。
每个点存他的值(val)、这颗子树的负数的总数(neg)、这颗子树的结点的总数(size)、这颗子树的权和(sum)。
可以发现正数和负数的排列是一样的(FIFO),那么插入的正数前面有多少个正数,那么插入的负数前面就有多少个负数,把这个多少个正数算出来,然后插负数的时候尽量往右插即可。
删除操作,在插入的时候记录正数和负数在那个结点上,删除的时候直接旋转到底删掉。
查询操作,因为我们把结点位置记录起来了,那么对于区间[a,b],在a所在的结点往上走,可以算出[a, ~)的权和,同理可以算出(~, b]的权和,然后这两个的和减去所有的数的和(容斥原理)就是这个查询的答案(由于总和一定是0,所以不用减了)。
代码(796MS):
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #include <queue> 6 using namespace std; 7 typedef long long LL; 8 9 const int MAXN = 2 * 100010; 10 const int n = 100000; 11 int weight[MAXN], child[MAXN][2], size[MAXN], neg[MAXN], val[MAXN], pre[MAXN]; 12 LL sum[MAXN]; 13 int pos[MAXN]; 14 int stk[MAXN], top, node_cnt; 15 16 int m, p, x, root; 17 char s[10]; 18 19 priority_queue<int> Q; 20 int int_cnt; 21 22 void test(int x) { 23 if(child[x][0]) test(child[x][0]); 24 cout<<val[x]<<" "<<sum[x]<<" "<<x<<" "<<pre[x]<<" "<<(child[pre[x]][1] == x)<<endl; 25 //cout<<val[x]<<endl; 26 if(child[x][1]) test(child[x][1]); 27 } 28 29 void init() { 30 while(!Q.empty()) Q.pop(); 31 int_cnt = top = node_cnt = 0; 32 } 33 34 int new_int() { 35 if(!Q.empty()) { 36 int ret = -Q.top(); Q.pop(); 37 return ret; 38 } 39 return ++int_cnt; 40 } 41 42 int new_node(int f, int v) { 43 int x = (top ? stk[top--] : ++node_cnt); 44 pre[x] = f; 45 sum[x] = val[x] = v; 46 if(v < 0) pos[n - v] = x; 47 else pos[v] = x; 48 size[x] = 1; neg[x] = (v < 0); 49 weight[x] = rand(); 50 child[x][0] = child[x][1] = 0; 51 return x; 52 } 53 54 void update(int x) { 55 sum[x] = sum[child[x][0]] + sum[child[x][1]] + val[x]; 56 size[x] = size[child[x][0]] + size[child[x][1]] + 1; 57 neg[x] = neg[child[x][0]] + neg[child[x][1]] + (val[x] < 0); 58 } 59 60 void rotate(int &x, int t) { 61 int y = child[x][t]; 62 child[x][t] = child[y][t ^ 1]; 63 child[y][t ^ 1] = x; 64 pre[y] = pre[x]; pre[x] = y; 65 pre[child[x][t]] = x; 66 update(x); update(y); 67 x = y; 68 } 69 70 void insert1(int f, int &x, int k, int v) { 71 if(x == 0) x = new_node(f, v); 72 else { 73 int t = (size[child[x][0]] + 1 <= k); 74 insert1(x, child[x][t], k - t * (size[child[x][0]] + 1), v); 75 if(weight[child[x][t]] < weight[x]) rotate(x, t); 76 } 77 update(x); 78 } 79 80 int cnt_pos(int x, int t) { 81 if(!x) return 0; 82 int ret = cnt_pos(pre[x], child[pre[x]][1] == x); 83 if(t == 1) ret += size[child[x][0]] - neg[child[x][0]] + (val[x] > 0); 84 return ret; 85 } 86 87 void insert2(int f, int &x, int k, int v) { 88 if(x == 0) x = new_node(f, v); 89 else { 90 int t = (neg[child[x][0]] + (val[x] < 0) <= k); 91 insert2(x, child[x][t], k - t * (neg[child[x][0]] + (val[x] < 0)), v); 92 if(weight[child[x][t]] < weight[x]) rotate(x, t); 93 } 94 update(x); 95 } 96 97 void remove(int &x) { 98 if(child[x][0] && child[x][1]) { 99 int t = weight[child[x][0]] < weight[child[x][1]]; 100 rotate(x, t); 101 remove(child[x][t ^ 1]); 102 } else { 103 stk[++top] = x; 104 pre[child[x][0]] = pre[child[x][1]] = pre[x]; 105 x = child[x][0] + child[x][1]; 106 } 107 if(x > 0) update(x); 108 } 109 110 LL query1(int x, int t) { 111 if(!x) return 0; 112 LL ret = query1(pre[x], child[pre[x]][1] == x); 113 if(t == 0) ret += sum[child[x][1]] + val[x]; 114 return ret; 115 } 116 117 LL query2(int x, int t) { 118 if(!x) return 0; 119 LL ret = query2(pre[x], child[pre[x]][1] == x); 120 if(t == 1) ret += sum[child[x][0]] + val[x]; 121 return ret; 122 } 123 124 LL query(int x, int a, int b) { 125 LL ret = query1(pre[a], child[pre[a]][1] == a) + sum[child[a][1]]; 126 ret += query2(pre[b], child[pre[b]][1] == b) + sum[child[b][0]]; 127 return ret; 128 } 129 130 void update_parent(int t) { 131 while(t) update(t), t = pre[t]; 132 } 133 134 int main() { 135 for(int t = 1; ; ++t) { 136 if(scanf("%d", &m) == EOF) break; 137 init(); 138 printf("Case #%d: ", t); 139 root = 0; 140 while(m--) { 141 scanf("%s%d", s, &x); 142 if(*s == 'i') { 143 int tmp = new_int(); 144 insert1(0, root, x, tmp); 145 int k = cnt_pos(pos[tmp], 1) - 1; 146 insert2(0, root, k, -tmp); 147 } 148 if(*s == 'r') { 149 if(root == pos[x]) { 150 remove(root); 151 } 152 else { 153 int t = pos[x], p = pre[t]; 154 remove(child[p][child[p][1] == t]); 155 update_parent(p); 156 } 157 int y = x + n; 158 if(root == pos[y]) { 159 remove(root); 160 } 161 else { 162 int t = pos[y], p = pre[t]; 163 remove(child[p][child[p][1] == t]); 164 update_parent(p); 165 } 166 Q.push(-x); 167 } 168 if(*s == 'q') { 169 printf("%I64d ", query(root, pos[x], pos[x + n])); 170 } 171 //test(root); 172 } 173 } 174 }