HDU 4441 Queue Sequence(优先队列+Treap树)(2012 Asia Tianjin Regional Contest)

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.
 
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.
 
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.
 
题目大意:这题太难描述了不讲了,亏出题人能想出这么难讲的题……
思路:对于插入最小正数,有一个优先队列维护即可(咋这么多人喜欢用线段树……)
然后序列用一个平衡树维护,我选择了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:\n", 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\n", query(root, pos[x], pos[x + n]));

170             }

171                 //test(root);

172         }

173     }

174 }
View Code

 

你可能感兴趣的:(sequence)