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
  • 相关阅读:
    Web API 强势入门指南
    毫秒必争,前端网页性能最佳实践
    Windbg Extension NetExt 使用指南 【3】 ---- 挖掘你想要的数据 Managed Heap
    Windbg Extension NetExt 使用指南 【2】 ---- NetExt 的基本命令介绍
    Windbg Extension NetExt 使用指南 【1】 ---- NetExt 介绍
    WCF : 修复 Security settings for this service require Windows Authentication but it is not enabled for the IIS application that hosts this service 问题
    透过WinDBG的视角看String
    Microsoft Azure Web Sites应用与实践【4】—— Microsoft Azure网站的“后门”
    企业IT管理员IE11升级指南【17】—— F12 开发者工具
    WCF : 如何将NetTcpBinding寄宿在IIS7上
  • 原文地址:https://www.cnblogs.com/sto324/p/11380218.html
Copyright © 2011-2022 走看看