[NOI2004]郁闷的出纳员

本题涉及到的操作有:单点插入,区间更新,删除比x小的数,询问第k大的数。

可以用splay维护一个有序的序列。

先给splay分配一个虚拟结点,

虚拟结点的v等于-INF,这样保证了虚拟结点的左儿子始终为null。。

插入操作:

计算比x小的数的个数k,对原序列split。。。 

有序插入,使得序列始终保持   -oo  10 20 30 40 这样子。

--记得pushdown(), 要把所有值算出来,才能确定大小。下同。

void add(int x) {//从小到大插入x
  cnt++;
  Node *p = ss.root;
  int k = 0;
  while ( p != null ) {
    p->pushdown();
    if(p->v > x) p = p->ch[0];
    else {
      k += p->ch[0]->s + 1;
      p = p->ch[1];
    }
  }
  Node *left, *right;
  split(ss.root, k, left, right);
  Node *mid = new Node();
  mid->ch[0] = mid->ch[1] = null;
  mid->s = 1;//很关键
  mid->v = x; mid->lazy = 0;

  ss.root = merge(merge(left, mid), right);
}

 删除比x小的数:

同样是计算比x小的个数k,然后要特殊判断一下k是否为1;

把虚拟结点单提出来,那么要删除的结点一共有k-1个。。

void del(int x) {//删除比x小的数
  int k = 0;
  Node *p = ss.root;
  while ( p != null ) {
    p->pushdown();
    if(p->v >= x) p = p->ch[0];
    else {
      k += p->ch[0]->s + 1;
      p = p->ch[1];
    }
  }
  if(k == 1) return;
  Node *left, *mid, *right, *o;
  split(ss.root, 1, left, o);                                                                 
  split(o, k-1, mid, right);
  ss.root = merge(left, right);

  cnt -= k-1;
  leave += k-1;
}

 区间更新:

把虚拟结点提出来,对剩下的那些有序序列打延迟标记。

void updata(int c) {
  Node *left, *right;
  split(ss.root, 1, left, right);
  right->v += c;
  right->lazy += c;
  ss.root = merge(left, right);
}

询问第k大数:

要找第k大数,只需要找包括虚拟结点在内的第cnt-k+1个数。

int query(int k) {//询问第k大的数
  if(cnt-1 < k) return -1;
  Node *left, *mid, *right, *o;
  k = cnt-k+1; //printf ( "k=%d
", k );
  split(ss.root, k, left, right); //printf("left:");debug(left);puts("");
  ss.root = merge(left, right);
  return left->v;
}

数组法: 

  void add(int x) {
    ++cnt;
    int k = 0, p = root;
    while ( p ) {
      push_down(p);
      if ( val[p] > x ) p = ch[p][0];
      else {
        k += sz[ch[p][0]] + 1;
        p = ch[p][1];
      }
    }
    RotateTo(k-1, 0);
    RotateTo(k, root);
    int key;
    NewNode(key, x);
    ch[ch[root][1]][0] = key;
    pre[key] = ch[root][1];
    push_up(ch[root][1]);
    push_up(root);
  }
  void del(int x) {
    int k = 0, p = root;                                                                                
    while ( p ) {
      push_down(p);
      if ( val[p] >= x ) p = ch[p][0];
      else {
        k += sz[ch[p][0]] + 1;
        p = ch[p][1];
      }
    }
    RotateTo(0, 0);
    RotateTo(k, root);
    int key = ch[ch[root][1]][0];
    ch[ch[root][1]][0] = 0;
    push_up(root);
    cnt -= sz[key];
    leave += sz[key];
  }
  void updata(int c) {
    RotateTo(0, 0);
    RotateTo(cnt+1, root);
    int key = ch[ch[root][1]][0];
    val[key] += c;
    lazy[key] += c;
    push_up(root);
  }
  int query(int k) {//询问第k大的数
    if ( k > cnt ) return -1;
    k = cnt - k + 1;
    RotateTo(k-1, 0);
    RotateTo(k+1, root);
    int key = ch[ch[root][1]][0];
    return val[key];
  }
原文地址:https://www.cnblogs.com/Accoral/p/3148764.html