zoukankan      html  css  js  c++  java
  • [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];
      }
  • 相关阅读:
    Docker-compose编排微服务顺序启动解决方案
    在笔记本上使用virtualbox搭建lvs dr 实验遇到的问题
    MongoDB安装配置(RedHat/CentOS)
    wget 用法
    Ubuntu查看crontab运行日志
    CentOS-6.5安装Zabbix 3.0.4
    centos 6 安装vsftpd与PAM虚拟用户
    python socket常用接口说明
    cmake 构建工程
    std::vector的下标访问和迭代器访问的效率
  • 原文地址:https://www.cnblogs.com/Accoral/p/3148764.html
Copyright © 2011-2022 走看看