• 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:
    ", 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 }
    View Code
  • 相关阅读:
    如何自己手写一个热加载(转)
    阻塞I/O、非阻塞I/O和I/O多路复用、怎样理解阻塞非阻塞与同步异步的区别?
    Java NIO浅析 转至 美团技术团队
    mysql在线修改表结构大数据表的风险与解决办法归纳(转)
    MySQL性能优化
    Tomcat Connector(BIO, NIO, APR)三种运行模式(转)
    redis 单线程的理解
    Spring 中的bean 是线程安全的吗?
    Spring 自定义注解,结合AOP,配置简单日志注解 (转)
    redis 分布式锁
  • 原文地址:https://www.cnblogs.com/oyking/p/3352682.html
Copyright © 2020-2023  润新知