• [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];
      }
  • 相关阅读:
    【贪心算法】POJ-3040 局部最优到全局最优
    【贪心算法】POJ-1017
    【贪心算法】POJ-2393 简单贪心水题
    【贪心算法】POJ-3190 区间问题
    项目选题报告(团队)
    结对项目第一次作业——原型设计
    第三次作业团队展示
    软工实践第二次作业——数独
    软件工程实践第一次作业--准备
    字符串
  • 原文地址:https://www.cnblogs.com/Accoral/p/3148764.html
Copyright © 2020-2023  润新知