zoukankan      html  css  js  c++  java
  • [NOI2004]郁闷的出纳员

    题目描述

    有一个公司,有四种操作:

    1.拉一个人进入公司,有初始工资

    2.每个人的工资加上x

    3.每个人的工资减去x

    4.查询第k大的工资

    当一个人工资低于m时他就会立即离开公司。

    要求对于询问输出答案,最后输出离开的人的个数。

    题解

    查询第k大就用平衡树搞。

    主要要解决的就是如何高效的帮助人离开,可以想到找到第一个满足留在公司的人,他前面的人都不满足删掉即可。

    2.3操作肯定是懒惰标记搞,因为是每个人平等的(同加同减),所以不会搞乱相对大小,在访问这个点的时候信息是更新好了的。用ret记录第一个满足的人,如果这个人的工资满足,ret就是这个人,然后往左儿子走,不然走右儿子。(可能有点绕,需要理解)

    如果ret没记录说明全部都要走(好惨),这时特判搞一搞就好。记录了就旋到根,去掉根的左儿子。

    有些地方要注意边界,因为splay可能没元素。

    因为工资可能一样,所以要多记录一个num。

    在在splay里面走的时候要push_down!!!!插入,删除,查k大

    一个人初始工资不满足离开不加入最后答案(坑死我)。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=100005;
    int n,m,root,cnt,ans;
    struct Splay{
      int fa,s[2],size,tag,val,num;
    }tr[maxn];
    
    template<class T>inline void read(T &x){
      x=0;int f=0;char ch=getchar();
      while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
      while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
      x= f ? -x : x ;
    }
    
    void put_tag(int x,int val){
      if(!x) return ;
      tr[x].val+=val;
      tr[x].tag+=val;
    }
    
    void push_down(int x){
      if(!tr[x].tag) return ;
      put_tag(tr[x].s[0],tr[x].tag);
      put_tag(tr[x].s[1],tr[x].tag);
      tr[x].tag=0;
    }
    
    void update(int x){
      tr[x].size=tr[tr[x].s[0]].size+tr[tr[x].s[1]].size+tr[x].num;
    }
    
    int get(int x){return tr[tr[x].fa].s[1]==x;}
    
    void connect(int x,int y,int d){
      tr[x].fa=y;
      tr[y].s[d]=x;
    }
    
    void rotate(int x){
      int f=tr[x].fa,ff=tr[f].fa;
      int d1=get(x),d2=get(f);
      int cs=tr[x].s[d1^1];
      connect(x,ff,d2);
      connect(f,x,d1^1);
      connect(cs,f,d1);
      update(f);
      update(x);
    }
    
    void splay(int x,int go){
      if(go==root) root=x;
      go=tr[go].fa;
      while(tr[x].fa!=go){
        int f=tr[x].fa;
        if(tr[f].fa==go) rotate(x);
        else if(get(x)==get(f)) {rotate(f);rotate(x);}
        else {rotate(x);rotate(x);}
      }
    }
    
    void debug(int x){
      if(!x) return ;
      push_down(x);
      debug(tr[x].s[0]);
      for(int i=1;i<=tr[x].num;i++) printf("%d ",tr[x].val);
      debug(tr[x].s[1]);
    }
    
    void insert(int val){
      if(!root){
        root=++cnt;
        tr[root]=(Splay){0,{0,0},1,0,val,1};
        return ;
      }
      int now=root;
      while(1){
        tr[now].size++;
        push_down(now);
        if(val==tr[now].val){
          tr[now].num++;
          break;
        }
        int o=val>tr[now].val;
        if(!tr[now].s[o]){
          tr[++cnt]=(Splay){now,{0,0},1,0,val,1};
          tr[now].s[o]=cnt;
          now=cnt;
          break;
        }
        now=tr[now].s[o];
      }
      splay(now,root);
    }
    
    void get_it(){
      if(!root) return ;
      int now=root,ret=0;
      while(1){
        if(!now) break;
        push_down(now);
        if(tr[now].val>=m){
          ret=now;
          now=tr[now].s[0];
        }
        else now=tr[now].s[1];
      }
      if(!ret) {ans+=tr[root].size;root=0;return ;}
      splay(ret,root);
      if(!tr[root].s[0]) return ;
      ans+=tr[tr[root].s[0]].size;
      tr[root].s[0]=0;
      update(root);
    }
    
    int find(int k){
      int now=root;
      if(!now||tr[now].size<k) return -1;
      while(1){
        push_down(now);
        if(tr[tr[now].s[1]].size>=k) {now=tr[now].s[1];continue;}
        k-=tr[tr[now].s[1]].size;
        if(tr[now].num>=k) break;
        k-=tr[now].num;
        now=tr[now].s[0];
      }
      splay(now,root);
      return tr[root].val;
    }
    
    int main(){
      read(n);read(m);
      for(int i=1;i<=n;i++){
        char op[2];
        scanf("%s",op);
        if(op[0]=='I'){
          int val;
          read(val);
          if(val<m) continue;
          insert(val);
        }
        else if(op[0]=='A'){
          int val;
          read(val);
          put_tag(root,val);
        }
        else if(op[0]=='S'){
          int val;
          read(val);
          put_tag(root,-val);
          get_it();
        }
        else {
          int k;
          read(k);
          printf("%d
    ",find(k));
        }
        //putchar(10);
        //debug(root);
        //putchar(10);
      }
      printf("%d",ans);
    }
    View Code
  • 相关阅读:
    Medium | LeetCode 142. 环形链表 II
    Easy | LeetCode 141. 环形链表
    Hard | LeetCode 23. 合并K个升序链表 | 分治 | 优先队列
    std(19)内置算法find find_if
    stl(18)内置算法for_each transform
    C++引用和指针比较 指针常量和常量指针
    #pragma once和#ifndef用法
    c++变量的一些注意点 extern关键字的使用
    比特 字节 地址 类型 编码 32位 64位
    stl(16)stl内置的一些函数对象
  • 原文地址:https://www.cnblogs.com/sto324/p/11380218.html
Copyright © 2011-2022 走看看