zoukankan      html  css  js  c++  java
  • 【题解】【bzoj 1503】【NOI2004】郁闷的出纳员

    传送门

    前置芝士

    总体思路

    首先,I 和 F 看起来比较清真,应该随便来个平衡树或者线段树之类的瞎维护一下就好。

    主要是 A 和 S。

    算法 1:

    暴力加。

    算法 2:

    仿照线段树,打 Tag.

    我们维护一个 Tag 变量和一个 minwage 变量。

    别问我为什么是 wage,我也不知道。

    I 操作的时候,要把给定的工资减去 Tag

    F 操作的时候,找到之后加上 Tag 再输出即可。

    A 操作的时候,设输入的第二个数为 delt,则 Tag+=delt,minwage-=delt; 即可。

    S 操作同理 A,只不过要处理一下工资过低的人们大规模 sudo rm -rf / 加跑路的情况。

    我们用无旋 treap 维护这个过程,除了大规模跑路的情况以外,所有操作都应该已经很简单了。

    至于删除所有工资低于给定数的人,在无旋 treap 上其实也就很简单了,把整棵树 split 成两颗(无旋 treap 基本操作),然后乱搞一下就好了(见代码)。

    事实上啰嗦这么半天感觉还不如直接上代码简单。

    奇怪的点:立刻离开公司的人不计入最后一行的答案。

    代码:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=1e7+9;
    struct node{
    	int val;
    	int rnd;
    	int l,r;
    	int sz;
    }tree[N];
    int n;
    int tot,root;
    int Tag,leavetot;
    int minwage; 
    int newnode(int x){
    	tree[++tot]=(node){x,rand(),0,0,1};
    	return tot;
    }
    void pushup(int x){
    	tree[x].sz=tree[tree[x].l].sz+tree[tree[x].r].sz+1;
    }
    void split(int now,int k,int&l,int&r){
    	if(!now){
    		l=r=0;
    		return;
    	}
    	if(tree[now].val<=k){
    		l=now;
    		split(tree[now].r,k,tree[now].r,r);
    	}
    	else{
    		r=now;
    		split(tree[now].l,k,l,tree[now].l);
    	}
    	pushup(now);
    }
    int merge(int x,int y){
    	if(!x)return y;
    	if(!y)return x;
    	if(tree[x].rnd<tree[y].rnd){
    		tree[x].r=merge(tree[x].r,y);
    		return pushup(x),x;
    	}
    	else{
    		tree[y].l=merge(x,tree[y].l);
    		return pushup(y),y;
    	}
    }
    void insert(int val){
    	int x,y;
    	split(root,val,x,y);
    	root=merge(merge(x,newnode(val)),y);
    }
    int getval(int rk,int pos=root){
    	while(1){
    		int v=tree[tree[pos].l].sz;
    		if(rk==v+1)return tree[pos].val;
    		else if(rk<=v)pos=tree[pos].l;
    		else rk-=v+1,pos=tree[pos].r;
    	}
    }
    signed main(){
    	srand(time(0));
    	cin>>n>>minwage;
    	while(n--){
    		char op;cin>>op;
    		if(op=='I'){
    			int wage;cin>>wage;
    			wage-=Tag;
    			if(wage>=minwage)insert(wage);
    		}
    		else if(op=='A'){
    			int delt;cin>>delt;
    			Tag+=delt,minwage-=delt;
    		}
    		else if(op=='S'){
    			int delt;cin>>delt;
    			Tag-=delt,minwage+=delt;
    			int x,y;
    			split(root,minwage-1,x,y);
    			leavetot+=tree[x].sz;
    			root=y;
    		}
    		else{
    			int k;cin>>k;
    			if(k>tree[root].sz)cout<<-1<<endl;
    			else cout<<getval(tree[root].sz-k+1)+Tag<<endl;
    		}
    	}cout<<leavetot<<endl;
    	return 0;
    }
    

    不懂的欢迎留言 AWA.

    Over.

  • 相关阅读:
    STL中的stack(堆栈)
    单链表的创建与删除
    面试题四 从尾到头打印链表
    第 1 章 第 2 题 空间敏感排序问题 位向量实现( bitset位向量 )
    第 1 章 第 2 题 位向量的数组实现问题 位运算实现
    第 1 章 第 1 题 高级语言的排序问题 C++标准算法实现
    面试题三 替换空格
    面试题二 二维数组中的查找
    面试题一 赋值运算符函数
    不为客户连接创建子进程的并发回射服务器( poll实现 )
  • 原文地址:https://www.cnblogs.com/unyieldingtrilobite/p/13549058.html
Copyright © 2011-2022 走看看