• COGS314. [NOI2004] 郁闷的出纳员


            ★★★   输入文件:cashier.in   输出文件:cashier.out   简单对比

                        时间限制:1 s   内存限制:128 MB

    【问题描述】

    OIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一份不错的工 作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资。如果他心情好,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把 他们的工资扣除一个相同的量。我真不知道除了调工资他还做什么其它事情。

    工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离 开公司,并且再也不会回来了。每位员工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员 工,我就得为他新建一个工资档案。

    老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第k多的员工拿多少工资。每当这时,我就不得不对数万个员工进行一次漫长的排序,然后告诉他答案。

    好了,现在你已经对我的工作了解不少了。正如你猜的那样,我想请你编一个工资统计程序。怎么样,不是很困难吧?

    【输入文件】

    第一行有两个非负整数n和min。n表示下面有多少条命令,min表示工资下界。接下来的n行,每行表示一条命令。命令可以是以下四种之一:

    • 名称 格式 作用
    • I命令 I_k 新建一个工资档案,初始工资为k。如果某员工的初始工资低于工资下界,他将立刻离开公司(不计入离开总数)。
    • A命令 A_k 把每位员工的工资加上k
    • S命令 S_k 把每位员工的工资扣除k
    • F命令 F_k 查询第k多的工资

    _(下划线)表示一个空格,I命令、A命令、S命令中的k是一个非负整数,F命令中的k是一个正整数。 在初始时,可以认为公司里一个员工也没有。

    【输出文件】

    输出文件的行数为F命令的条数加一。

    对于每条F命令,你的程序要输出一行,仅包含一个整数,为当前工资第k多的员工所拿的工资数,如果k大于目前员工的数目,则输出-1。

    输出文件的最后一行包含一个整数,为离开公司的员工的总数。


    【样例输入】

    9 10
    I 60
    I 70
    S 50
    F 2
    I 30
    S 15
    A 5
    F 1
    F 2
    

    【样例输出】

    10
    20
    -1
    2
    

    【约定】

    • I命令的条数不超过100000
    • A命令和S命令的总条数不超过100
    • F命令的条数不超过100000
    • 每次工资调整的调整量不超过1000
    • 新员工的工资不超过100000

    题解:

      对于每次工资的加减,如果加工资,让工资的下线MIN减去这个数,如果减工资,让工资的下线MIN加上这个数,就是用一种相对运动的思想。

      再记录一个delta变量,来处理新加入的员工。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<cmath>
      6 #include<queue>
      7 #include<vector>
      8 #include<algorithm>
      9 using namespace std;
     10 typedef long long LL;
     11 const LL maxn=100010;
     12 char s[5];
     13 LL root,tot,N,MIN,sum,delta;
     14 LL key[maxn],lc[maxn],rc[maxn],siz[maxn];
     15 void r_rotate(LL &rt){
     16     LL k=lc[rt];
     17     lc[rt]=rc[k];
     18     rc[k]=rt;
     19     siz[k]=siz[rt];
     20     siz[rt]=siz[lc[rt]]+siz[rc[rt]]+1;
     21     rt=k;
     22 }
     23 void l_rotate(LL &rt){
     24     LL k=rc[rt];
     25     rc[rt]=lc[k];
     26     lc[k]=rt;
     27     siz[k]=siz[rt];
     28     siz[rt]=siz[lc[rt]]+siz[rc[rt]]+1;
     29     rt=k;
     30 }
     31 void Maintain(LL &rt,bool flag){
     32     if(flag==false){
     33         if(siz[lc[lc[rt]]]>siz[rc[rt]]) r_rotate(rt);
     34         else if(siz[rc[lc[rt]]]>siz[rc[rt]]){
     35             l_rotate(lc[rt]);
     36             r_rotate(rt);
     37         }
     38         else return ;
     39     }
     40     else{
     41         if(siz[rc[rc[rt]]]>siz[lc[rt]]) l_rotate(rt);
     42         else if(siz[lc[rc[rt]]]>siz[lc[rt]]){
     43             r_rotate(rc[rt]);
     44             l_rotate(rt);
     45         }
     46         else return ;
     47     }
     48     Maintain(lc[rt],0); Maintain(rc[rt],1);
     49     Maintain(rt,1); Maintain(rt,0);
     50 }
     51 void insert(LL &rt,LL v){
     52     if(rt==0){
     53         rt=++tot;
     54         siz[rt]=1;
     55         lc[rt]=rc[rt]=0;
     56         key[rt]=v;
     57         return ;
     58     }
     59     siz[rt]++;
     60     if(v<=key[rt]) insert(lc[rt],v);
     61     else insert(rc[rt],v);
     62     Maintain(rt,1); Maintain(rt,0);
     63 }
     64 LL Delete(LL &rt,LL v){
     65     LL ans;
     66     siz[rt]--;
     67     if(v==key[rt]||(v<key[rt]&&lc[rt]==0)||(v>key[rt]&&rc[rt]==0)){
     68         ans=key[rt];
     69         if(lc[rt]==0||rc[rt]==0) rt=lc[rt]+rc[rt];
     70         else key[rt]=Delete(lc[rt],key[rt]+1);
     71         return ans;
     72     }
     73     else if(v<key[rt]) ans=Delete(lc[rt],v);
     74     else ans=Delete(rc[rt],v);
     75     return ans;
     76 }
     77 LL select(LL &rt,LL k){
     78     if(k==siz[lc[rt]]+1) return key[rt];
     79     if(k<=siz[lc[rt]]) return select(lc[rt],k);
     80     else return select(rc[rt],k-1-siz[lc[rt]]);
     81 }
     82 bool find(LL &rt,LL v){
     83     if(rt==0) return false;
     84     else if(v==key[rt]) return true;
     85     else if(v<key[rt]) return find(lc[rt],v);
     86     else if(v>key[rt]) return find(rc[rt],v);
     87 }
     88 LL pred(LL &rt,LL v){
     89     if(rt==0) return v;
     90     if(v<=key[rt]) return pred(lc[rt],v);
     91     else{
     92         LL ans=pred(rc[rt],v);
     93         if(ans==v) return key[rt];
     94         return ans;
     95     }
     96 }
     97 void Clear(){
     98     for(;;){
     99         LL k=pred(root,MIN);
    100         if(find(root,k)==true&&k<MIN) Delete(root,k),sum++;
    101         else break;
    102     }
    103 }
    104 int main(){
    105     scanf("%lld%lld",&N,&MIN);
    106     for(LL i=1,tmp;i<=N;i++){
    107         scanf("%s%lld",s,&tmp);
    108         if(s[0]=='I'){
    109             if(tmp-delta<MIN){
    110                 continue;
    111             }
    112             insert(root,tmp-delta);
    113         }
    114         else if(s[0]=='A'){//增加工资 
    115             MIN-=tmp;//要求标准下降 
    116             delta+=tmp; 
    117             Clear();
    118         }
    119         else if(s[0]=='S'){//减少工资 
    120             MIN+=tmp;//要求标准上升 
    121             delta-=tmp; 
    122             Clear();
    123         }
    124         else{
    125             if(siz[root]<tmp) puts("-1");
    126             else printf("%lld
    ",select(root,siz[root]-tmp+1)+delta);
    127         }
    128     }
    129     printf("%lld
    ",sum);
    130     return 0;
    131 }

       下面再来一发splay版的,但是splay的删除操作要十分小心,情况一定要考虑全面,还有边界情况,我跪了整整一天半。。。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cmath>
      5 #include<algorithm>
      6 #include<queue>
      7 #include<vector>
      8 using namespace std;
      9 typedef long long LL;
     10 const LL maxn=100010;
     11 LL key[maxn],lc[maxn],rc[maxn],fa[maxn],siz[maxn];
     12 LL tot,root;
     13 char s[5];
     14 LL N,MIN,sum,delta;
     15 void update(LL x){
     16     siz[x]=siz[lc[x]]+1+siz[rc[x]];
     17 }
     18 void r_rotate(LL x){
     19     LL y=fa[x];
     20     lc[y]=rc[x]; 
     21     if(rc[x]!=0) fa[rc[x]]=y; 
     22     fa[x]=fa[y];
     23     if(y==lc[fa[y]]) lc[fa[y]]=x;
     24     else rc[fa[y]]=x;
     25     fa[y]=x; rc[x]=y;
     26     update(x); update(y);
     27 }
     28 void l_rotate(LL x){
     29     LL y=fa[x];
     30     rc[y]=lc[x];
     31     if(lc[x]!=0) fa[lc[x]]=y;
     32     fa[x]=fa[y];
     33     if(y==lc[fa[y]]) lc[fa[y]]=x;
     34     else rc[fa[y]]=x;
     35     fa[y]=x; lc[x]=y;
     36     update(x); update(y);
     37 }
     38 void splay(LL x,LL s){
     39     LL p;
     40     while(fa[x]!=s){
     41         p=fa[x];
     42         if(fa[p]==s){
     43             if(x==lc[p]) r_rotate(x);
     44             else l_rotate(x);
     45             break; 
     46         }
     47         if(x==lc[p]){
     48             if(p==lc[fa[p]]) r_rotate(p),r_rotate(x);
     49             else r_rotate(x),l_rotate(x);
     50         }
     51         else{
     52             if(p==rc[fa[p]]) l_rotate(p),l_rotate(x);
     53             else l_rotate(x),r_rotate(x);
     54         }
     55     }
     56     if(s==0) root=x;
     57     update(x);
     58 }
     59 void New_node(LL &x,LL fath,LL v){//建立新节点 
     60     x=++tot;
     61     lc[x]=rc[x]=0; siz[x]=1;
     62     fa[x]=fath;
     63     key[x]=v;
     64 }
     65 void insert(LL v){//插入新节点 
     66     if(root==0){
     67         New_node(root,0,v);
     68         return ;
     69     }
     70     LL p,x=root;
     71     while(x!=0){
     72         p=x;
     73         if(v<=key[x]) siz[x]++,x=lc[x];
     74         else siz[x]++,x=rc[x];
     75     }
     76     if(v<=key[p]) New_node(lc[p],p,v);
     77     else New_node(rc[p],p,v);
     78     splay(tot,0);
     79 }
     80 LL find(LL v){//查找在这棵树中键值为v的节点 
     81     LL x=root;
     82     while(x!=0){
     83         if(v<key[x]) x=lc[x];
     84         else if(v>key[x]) x=rc[x];
     85         else if(v==key[x]){
     86             splay(x,0);
     87             return x;
     88         }
     89     }
     90     return -1;
     91 }
     92 LL getmax(LL x){//找到以x为根的最大值 
     93     while(rc[x]!=0) x=rc[x];
     94     return x;
     95 }
     96 LL getmin(LL x){//找到以x为根的最小值 
     97     while(lc[x]!=0) x=lc[x];
     98     return x;
     99 }
    100 LL getpre(LL x){//找到节点x的前驱 
    101     splay(x,0);
    102     if(lc[x]==0) return -1;
    103     return getmax(lc[x]);
    104 }
    105 LL getne(LL x){//找到节点x的后继
    106     splay(x,0);
    107     if(rc[x]==0) return -1; 
    108     return getmin(rc[x]);
    109 }
    110 LL join(LL s1,LL s2){//把以s1和s2为根的子树合并,返回根 
    111     if(s1==0||s2==0){
    112         if(s1==0&&s2==0){
    113             rc[0]=0;
    114             return 0;    
    115         }
    116         if(s1==0){
    117             rc[fa[s2]]=0; rc[0]=s2; fa[s2]=0;
    118             siz[root]=1;
    119             return s2;        
    120         }
    121         else{
    122             lc[fa[s1]]=0; rc[0]=s1; fa[s1]=0;
    123             siz[root]=1;
    124             return s1;
    125         }
    126     }
    127     LL p=getmax(s1);//由getmax()函数可知,p要么是根的左孩子,要么是其父亲的右孩子, p肯定没有右孩子 
    128     if(p==lc[fa[p]]){//p是根的左孩子
    129         if(lc[p]!=0) //如果p有左孩子 
    130             lc[fa[p]]=lc[p],fa[lc[p]]=fa[p];//把p的左孩子接到父节点上         
    131         else lc[fa[p]]=0;
    132     }
    133     else{//p是其父亲的右孩子
    134         if(lc[p]!=0) //如果p有左孩子 
    135             rc[fa[p]]=lc[p],fa[lc[p]]=fa[p];//把p的左孩子接到父节点上
    136         else rc[fa[p]]=0;
    137     }
    138     update(fa[p]);//更新p的父亲s的iz值 
    139     LL rt=fa[s1];
    140     lc[rt]=rc[rt]=0; siz[rt]=1;//删去原根 
    141     if(s1!=p) lc[p]=s1,fa[s1]=p; //p的左孩子变成原根的左孩子
    142     rc[p]=s2; fa[s2]=p; //p的左孩子变成原根的右孩子
    143     fa[p]=0; rc[0]=p;
    144     update(p);
    145     return p;
    146 }
    147 void Delete(LL v){//删除一个键值为v的节点 
    148     LL x=find(v);
    149     root=join(lc[x],rc[x]);
    150 }
    151 
    152 LL findkth(LL x,LL k){//在以x为根的树中找第 k大 
    153     if(siz[lc[x]]+1==k) return key[x];
    154     if(siz[lc[x]]+1>k) return findkth(lc[x],k);
    155     return findkth(rc[x],k-siz[lc[x]]-1);
    156 }
    157 
    158 LL pred(LL rt,LL v){//返回比 v小的最大的数 
    159     if(rt==0) return v;
    160     if(v<=key[rt]) return pred(lc[rt],v);
    161     else{
    162         LL ans=pred(rc[rt],v);
    163         if(ans==v) return key[rt]; 
    164         return ans;
    165     }
    166 }
    167 void Clear(){
    168     for(;;){
    169         LL k=pred(root,MIN);
    170         if(find(k)!=-1&&k<MIN){
    171             Delete(k);
    172             sum++;    
    173         }
    174         else break;
    175     }
    176 }
    177 int main(){
    178     scanf("%lld%lld",&N,&MIN);
    179     for(LL i=1,tmp;i<=N;i++){
    180         scanf("%s%lld",s,&tmp);
    181         if(s[0]=='I'){
    182             if(tmp-delta<MIN){
    183                 continue;
    184             }
    185             insert(tmp-delta);
    186         }
    187         else if(s[0]=='A'){//增加工资 
    188             MIN-=tmp;//要求标准下降 
    189             delta+=tmp; 
    190             Clear();
    191         }
    192         else if(s[0]=='S'){//减少工资 
    193             MIN+=tmp;//要求标准上升 
    194             delta-=tmp; 
    195             Clear();
    196         }
    197         else{
    198             if(siz[root]<tmp) puts("-1");
    199             else printf("%lld
    ",findkth(root,siz[root]-tmp+1)+delta);
    200         }
    201     }
    202     printf("%lld
    ",sum);
    203     return 0;
    204 }
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cmath>
      5 #include<algorithm>
      6 #include<queue>
      7 #include<vector>
      8 using namespace std;
      9 typedef long long LL;
     10 const LL maxn=100010;
     11 LL key[maxn],lc[maxn],rc[maxn],fa[maxn],siz[maxn];
     12 LL tot,root;
     13 char s[5];
     14 LL N,MIN,sum,delta;
     15 void update(LL x){
     16     siz[x]=siz[lc[x]]+1+siz[rc[x]];
     17 }
     18 void r_rotate(LL x){
     19     LL y=fa[x];
     20     lc[y]=rc[x]; 
     21     if(rc[x]!=0) fa[rc[x]]=y; 
     22     fa[x]=fa[y];
     23     if(y==lc[fa[y]]) lc[fa[y]]=x;
     24     else rc[fa[y]]=x;
     25     fa[y]=x; rc[x]=y;
     26     update(x); update(y);
     27 }
     28 void l_rotate(LL x){
     29     LL y=fa[x];
     30     rc[y]=lc[x];
     31     if(lc[x]!=0) fa[lc[x]]=y;
     32     fa[x]=fa[y];
     33     if(y==lc[fa[y]]) lc[fa[y]]=x;
     34     else rc[fa[y]]=x;
     35     fa[y]=x; lc[x]=y;
     36     update(x); update(y);
     37 }
     38 void splay(LL x,LL s){
     39     LL p;
     40     while(fa[x]!=s){
     41         p=fa[x];
     42         if(fa[p]==s){
     43             if(x==lc[p]) r_rotate(x);
     44             else l_rotate(x);
     45             break; 
     46         }
     47         if(x==lc[p]){
     48             if(p==lc[fa[p]]) r_rotate(p),r_rotate(x);
     49             else r_rotate(x),l_rotate(x);
     50         }
     51         else{
     52             if(p==rc[fa[p]]) l_rotate(p),l_rotate(x);
     53             else l_rotate(x),r_rotate(x);
     54         }
     55     }
     56     if(s==0) root=x;
     57     update(x);
     58 }
     59 void New_node(LL &x,LL fath,LL v){//建立新节点 
     60     x=++tot;
     61     lc[x]=rc[x]=0; siz[x]=1;
     62     fa[x]=fath;
     63     key[x]=v;
     64 }
     65 void insert(LL v){//插入新节点 
     66     if(root==0){
     67         New_node(root,0,v);
     68         return ;
     69     }
     70     LL p,x=root;
     71     while(x!=0){
     72         p=x;
     73         if(v<=key[x]) siz[x]++,x=lc[x];
     74         else siz[x]++,x=rc[x];
     75     }
     76     if(v<=key[p]) New_node(lc[p],p,v);
     77     else New_node(rc[p],p,v);
     78     splay(tot,0);
     79 }
     80 LL find(LL v){//查找在这棵树中键值为v的节点 
     81     LL x=root;
     82     while(x!=0){
     83         if(v<key[x]) x=lc[x];
     84         else if(v>key[x]) x=rc[x];
     85         else if(v==key[x]){
     86             splay(x,0);
     87             return x;
     88         }
     89     }
     90     return -1;
     91 }
     92 LL getmax(LL x){//找到以x为根的最大值 
     93     while(rc[x]!=0) x=rc[x];
     94     return x;
     95 }
     96 LL getmin(LL x){//找到以x为根的最小值 
     97     while(lc[x]!=0) x=lc[x];
     98     return x;
     99 }
    100 LL getpre(LL x){//找到节点x的前驱 
    101     splay(x,0);
    102     if(lc[x]==0) return -1;
    103     return getmax(lc[x]);
    104 }
    105 LL getne(LL x){//找到节点x的后继
    106     splay(x,0);
    107     if(rc[x]==0) return -1; 
    108     return getmin(rc[x]);
    109 }
    110 LL join(LL s1,LL s2){//把以s1和s2为根的子树合并,返回根 
    111     if(s1==0||s2==0){
    112         if(s1==0&&s2==0){
    113             rc[0]=0;
    114             return 0;    
    115         }
    116         if(s1==0){
    117             rc[fa[s2]]=0; rc[0]=s2; fa[s2]=0;
    118             siz[root]=1;
    119             return s2;        
    120         }
    121         else{
    122             lc[fa[s1]]=0; rc[0]=s1; fa[s1]=0;
    123             siz[root]=1;
    124             return s1;
    125         }
    126     }
    127     LL p=getmax(s1);//由getmax()函数可知,p要么是根的左孩子,要么是其父亲的右孩子, p肯定没有右孩子 
    128     if(p==lc[fa[p]]){//p是根的左孩子
    129         if(lc[p]!=0) //如果p有左孩子 
    130             lc[fa[p]]=lc[p],fa[lc[p]]=fa[p];//把p的左孩子接到父节点上         
    131         else lc[fa[p]]=0;
    132     }
    133     else{//p是其父亲的右孩子
    134         if(lc[p]!=0) //如果p有左孩子 
    135             rc[fa[p]]=lc[p],fa[lc[p]]=fa[p];//把p的左孩子接到父节点上
    136         else rc[fa[p]]=0;
    137     }
    138     update(fa[p]);//更新p的父亲s的iz值 
    139     LL rt=fa[s1];
    140     lc[rt]=rc[rt]=0; siz[rt]=1;//删去原根 
    141     if(s1!=p) lc[p]=s1,fa[s1]=p; //p的左孩子变成原根的左孩子
    142     rc[p]=s2; fa[s2]=p; //p的左孩子变成原根的右孩子
    143     fa[p]=0; rc[0]=p;
    144     update(p);
    145     return p;
    146 }
    147 void Delete(LL v){//删除一个键值为v的节点 
    148     LL x=find(v);
    149     root=join(lc[x],rc[x]);
    150 }
    151 
    152 LL findkth(LL x,LL k){//在以x为根的树中找第 k大 
    153     if(siz[lc[x]]+1==k) return key[x];
    154     if(siz[lc[x]]+1>k) return findkth(lc[x],k);
    155     return findkth(rc[x],k-siz[lc[x]]-1);
    156 }
    157 
    158 LL pred(LL rt,LL v){//返回比 v小的最大的数 
    159     if(rt==0) return v;
    160     if(v<=key[rt]) return pred(lc[rt],v);
    161     else{
    162         LL ans=pred(rc[rt],v);
    163         if(ans==v) return key[rt]; 
    164         return ans;
    165     }
    166 }
    167 void Clear(){
    168     for(;;){
    169         LL k=pred(root,MIN);
    170         if(find(k)!=-1&&k<MIN){
    171             Delete(k);
    172             sum++;    
    173         }
    174         else break;
    175     }
    176 }
    177 int main(){
    178     freopen("cashier.in","r",stdin);
    179     freopen("cashier.out","w",stdout);
    180     scanf("%lld%lld",&N,&MIN);
    181     for(LL i=1,tmp;i<=N;i++){
    182         scanf("%s%lld",s,&tmp);
    183         if(s[0]=='I'){
    184             if(tmp-delta<MIN){
    185                 continue;
    186             }
    187             insert(tmp-delta);
    188         }
    189         else if(s[0]=='A'){//增加工资 
    190             MIN-=tmp;//要求标准下降 
    191             delta+=tmp; 
    192             Clear();
    193         }
    194         else if(s[0]=='S'){//减少工资 
    195             MIN+=tmp;//要求标准上升 
    196             delta-=tmp; 
    197             Clear();
    198         }
    199         else{
    200             if(siz[root]<tmp) puts("-1");
    201             else printf("%lld
    ",findkth(root,siz[root]-tmp+1)+delta);
    202         }
    203     }
    204     printf("%lld
    ",sum);
    205     return 0;
    206 }
  • 相关阅读:
    Fragment之三:根据屏幕尺寸加载不同的Fragment 分类: H1_ANDROID 2013-11-15 21:37 1162人阅读 评论(0) 收藏
    Fragment之一:Fragment入门 分类: H1_ANDROID 2013-11-15 18:16 2799人阅读 评论(2) 收藏
    Github android客户端源代码分析之一:环境搭建 分类: H1_ANDROID 2013-11-12 22:47 2829人阅读 评论(0) 收藏
    《30天自制操作系统》03_day_学习笔记
    《30天自制操作系统》02_day_学习笔记
    《30天自制操作系统》01_day_学习笔记
    湖大OJ-实验D----两个数的互素判定
    湖大OJ-实验B----CFG是P成员
    湖大OJ-实验A---- ADFA的可判定性
    关闭WIN10向微软发送浏览历史
  • 原文地址:https://www.cnblogs.com/CXCXCXC/p/5134019.html
Copyright © 2020-2023  润新知