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

 

posted @ 2013-10-05 18:27  Oyking  阅读(266)  评论(0编辑  收藏  举报