首页 > 其他分享 >P1486 [NOI2004] 郁闷的出纳员

P1486 [NOI2004] 郁闷的出纳员

时间:2023-11-17 13:16:08浏览次数:32  
标签:sz P1486 idx int pri 出纳员 up NOI2004 return

P1486 [NOI2004] 郁闷的出纳员

有两种思路,均使用fhq-treap实现

  1. 维护一个变量delta表示全局偏移量,对于新插入的数减去偏移量。使用fhq-treap,可以分裂出<mid的部分,直接丢掉。
  2. 直接用fhq-treap维护一个类似于线段树的懒标记,每次放在根上即可。

方法1

#include<iostream>
#include<random>
using namespace std;
random_device rnd;
mt19937 rd(rnd());
const int N=100010;
unsigned pri[N];
int n,m,rt,l[N],r[N],v[N],sz[N],idx,ans,delta;
#define up(p) sz[p]=sz[l[p]]+sz[r[p]]+1;
int add(int x){
	v[++idx]=x;
	sz[idx]=1;
	pri[idx]=rd();
	return idx;
}
void split(int p,int &x,int &y,int k){
	if(!p){
	    x=y=0;
	    return;
	}
	if(v[p]<=k){
	    x=p;
	    split(r[p],r[p],y,k);
	}
	else{
	    y=p;
	    split(l[p],x,l[p],k);
	}
	up(p);
}
int merge(int x,int y){
    if(!x||!y)return x|y;
    if(pri[x]>=pri[y]){
        r[x]=merge(r[x],y);
        up(x);
        return x;
    }
    else{
        l[y]=merge(x,l[y]);
        up(y);
        return y;
    }
}
int main(){
	#ifndef ONLINE_JUDGE
	freopen("1.in","r",stdin);
	#endif
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;++i){
		char x[3];
		int a,b,k;
		cin>>x>>k;
		if(*x=='I'){
			if(k<m)continue;
			split(rt,a,b,k-1-delta);
			rt=merge(merge(a,add(k-delta)),b);
		}
		else if(*x=='A')
			delta+=k;
		else if(*x=='F'){
		    if(k>sz[rt]){
		        cout<<"-1\n";
		        continue;
		    }
			int p=rt;
			while(p){
				if(k<=sz[r[p]])p=r[p];
				else if(k==sz[r[p]]+1){
					cout<<v[p]+delta<<'\n';
					break;
				}
				else k-=sz[r[p]]+1,p=l[p];
			}
		}
		else{
			delta-=k;
			split(rt,a,b,m-1-delta);
			rt=b;
			ans+=sz[a];
		}
	}
	cout<<ans;
	return 0;
}

方法2

#include<iostream>
#include<random>
using namespace std;
random_device rnd;
mt19937 rd(rnd());
const int N=300010;
unsigned pri[N];
int n,m,rt,l[N],r[N],v[N],sz[N],idx,f[N],ans;
#define up(p) sz[p]=sz[l[p]]+sz[r[p]]+1;
int add(int x){
	v[++idx]=x;
	sz[idx]=1;
	pri[idx]=rd();
	return idx;
}
void ch(int p,int k){
	v[p]+=k,f[p]+=k;
}
void down(int p){
	int &k=f[p];
	if(k)ch(l[p],k),ch(r[p],k),k=0;
}
void split(int p,int &x,int &y,int k){
	if(!p){
	    x=y=0;
	    return;
	}
	down(p);
	if(v[p]<=k){
	    x=p;
	    split(r[p],r[p],y,k);
	}
	else{
	    y=p;
	    split(l[p],x,l[p],k);
	}
	up(p);
}
int merge(int x,int y){
    if(!x||!y)return x|y;
    if(pri[x]>=pri[y]){
        down(x);
        r[x]=merge(r[x],y);
        up(x);
        return x;
    }
    else{
        down(y);
        l[y]=merge(x,l[y]);
        up(y);
        return y;
    }
}
int main(){
	#ifndef ONLINE_JUDGE
	freopen("1.in","r",stdin);
	#endif
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;++i){
		char x[2];
		int a,b,k;
		cin>>x>>k;
		if(*x=='I'){
			if(k<m)continue;
			split(rt,a,b,k-1);
			rt=merge(merge(a,add(k)),b);
		}
		else if(*x=='A')
			ch(rt,k);
		else if(*x=='F'){
		    if(k>sz[rt]){
		        cout<<"-1\n";
		        continue;
		    }
			int p=rt;
			while(p){
				down(p);
				if(k<=sz[r[p]])p=r[p];
				else if(k==sz[r[p]]+1){
					cout<<v[p]<<'\n';
					break;
				}
				else k-=sz[r[p]]+1,p=l[p];
			}
		}
		else{
			ch(rt,-k);
			split(rt,a,b,m-1);
			rt=b;
			ans+=sz[a];
		}
	}
	cout<<ans;
	return 0;
}

标签:sz,P1486,idx,int,pri,出纳员,up,NOI2004,return
From: https://www.cnblogs.com/wscqwq/p/17769528.html

相关文章

  • 洛谷 P2290 [HNOI2004] 树的计数(Prufer序列,Cayley 公式)
    传送门解题思路关于Prufer序列的构造,见OI-wiki这里直接放结论:一个Prufer序列与一个无根树一一对应度数为\(d_i\)的节点在序列中出现了\(d_i-1\)次\(\sum(d_i-1)=n-2\)n个点的完全图的生成树有\(n^{n-2}\)种所以相当于n-2个数(有重复的)进行全排列,答案即为:\[\frac......
  • [刷题笔记] Luogu P2285 [HNOI2004] 打鼹鼠
    ProblemAnalysis我们初始可以任意决定机器人的位置,状态很多,暴力显然会寄掉。不妨先贪心的思考一下。我们肯定希望机器人初始在最先出现鼹鼠的洞,因为出现在没有鼹鼠的洞是无效的。题目保证输入数据是严格按照出现时间递增顺序给出。定义\(f_i\)表示前\(i\)只鼹鼠最多能打到......
  • BZOJ1503 郁闷的出纳员 (Treap)
    DescriptionOIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一份不错的工作,但是令人郁闷的是,我们......
  • 郁闷的出纳员
    DescriptionlinkSolution显然是用平衡树维护,感觉Splay比较好维护。设\(delta\)表示当前总共加了多少工资,\(delta<0\)则表示扣了\(-delta\)的工资。对于I操......
  • P2292 [HNOI2004] L 语言
    给出字典(个数为\(n\))和文章(个数为\(m\)),求文章最大匹配前缀。\(n\leq20,m\leq50\),\(|s|\leq20,|t|\leq2\times10^6\)首先想到用AC自动机,在每个字串结尾标记串......
  • [HNOI2004] L 语言 题解(AC 自动机上 dp)
    前言:原版数据超弱,爆搜就能过(即洛谷里面80分的数据),在此不多说,这里讲的是正解。(如果不是正解我还敢写题解吗)唔······话说洛谷里的题解用的都有状压,蒟蒻表示这题不......