[HDOJ 4967] Handling the Past [线段树]

本文介绍了一种使用线段树解决乱序栈操作问题的方法。针对接收到的push、pop和top操作,通过时间戳排序并利用线段树实现即时返回特定时间点栈顶元素的功能。文章详细解释了算法原理及其实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作为一个服务器,你会收到一些关于一个栈的一些操作,他们分别是push,pop,top。由于网络原因,你收到操作的时间和操作实际发送的时间可能时不同的,甚至会是乱序的。

现在每个操作后边都会带着一个时间戳,所有的时间戳均不相同,代表这个操作时何时发送的。要求你对于收到的每一个top操作,立刻返回那个时刻的栈顶元素应该是什么。

观察可以发现,假设把目前收到的所有的操作都按照时间排序,那么对于时间t,返回的栈顶元素就是满足[l,t]区间内push操作恰好比pop操作的个数多1的最靠右的l。

所以我们用一棵线段树,对于push操作,在对应的时间位置上记录+1,pop操作记录-1。那么这棵线段树应该支持的操作有,点修改,查询满足[l,rr]的和等于x的最大的x。

又因为时间戳的范围时int的,所以我们要先进行离散化...

#include <cstdio>
#include <map>
#include <algorithm>
#include <utility>
#include <iostream>

using namespace std;

inline int in() {
	char c=getchar();
	while (c<'0'||c>'9') c=getchar();
	int ans=0;
	while (c>='0'&&c<='9') {
		ans=ans*10+c-'0';
		c=getchar();
	}
	return ans;
}
struct Query {
	int kind,value,time;
	void read() {
		char s[9];
		scanf("%s",s);
		if (s[1]=='u') {
			kind=1;
			value=in();
			time=in();
		} else if (s[1]=='o') {
			kind=2;
			time=in();
		} else {
			kind=3;
			time=in();
		}
	}
};
struct SeqNode {
	SeqNode *ls,*rs;
	int sum,rsum;
	void repair() {
		sum=ls->sum+rs->sum;
		rsum=max(ls->rsum+rs->sum,rs->rsum);
	}
};
SeqNode b[100000],*bp,*root;
Query a[50000];
map<int,int>c;
map<int,int>d;
int e[50001];
int n;

SeqNode *maketree(int l,int r) {
	SeqNode *ans=bp++;
	if (l==r) {
		ans->ls=ans->rs=NULL;
		ans->sum=ans->rsum=0;
	} else {
		int t=(l+r)/2;
		ans->ls=maketree(l,t);
		ans->rs=maketree(t+1,r);
		ans->repair();
	}
	return ans;
}
void set(SeqNode *from,int l,int r,int i,int x) {
	if (l==r) {
		from->sum=from->rsum=x;
	} else {
		int t=(l+r)/2;
		if (i<=t) set(from->ls,l,t,i,x);
		else set(from->rs,t+1,r,i,x);
		from->repair();
	}
}
pair<int,int> get(SeqNode *from,int l,int r,int rr,int sum) {
	//printf("%d %d %d %d\n",l,r,rr,sum);
	if (l==r) {
		if (from->sum==sum) return make_pair(l,0);
		else return make_pair(-1,from->sum);
	}
	int t=(l+r)/2;
	if (rr<=t) return get(from->ls,l,t,rr,sum);
	if (rr==r) {
		if (from->rsum<sum) return make_pair(-1,from->sum);
		if (from->rs->rsum>=sum) return get(from->rs,t+1,r,r,sum);
		else return get(from->ls,l,t,t,sum-from->rs->sum);
	} else {
		pair<int,int> tmp=get(from->rs,t+1,r,rr,sum);
		if (tmp.first!=-1) return tmp;
		if (from->ls->rsum<sum-tmp.second) 
			return make_pair(-1,tmp.second+from->ls->sum);
		else 
			return get(from->ls,l,t,t,sum-tmp.second);
	}
}
void print(SeqNode *from,int l,int r) {
	if (l!=r) {
		int t=(l+r)/2;
		print(from->ls,l,t);
		print(from->rs,t+1,r);
	} else {
		printf("%d ",from->sum);
	}
}
void print() {
	print(root,1,n);
	printf("\n");
}

int main() {
	int i,cas=1;
	while (scanf("%d",&n),n) {
		c.clear();
		d.clear();
		for (i=0;i<n;i++) {
			a[i].read();
			c[a[i].time]=1;
			d[a[i].time]=i;
		}
		i=1;
		for (map<int,int>::iterator it=c.begin();it!=c.end();it++,i++) {
			it->second=i;
			e[i]=it->first;
		}
		bp=b;
		root=maketree(1,n);
		printf("Case #%d:\n",cas++);
		//cerr<<cas<<' '<<n<<endl;
		//print();
		for (i=0;i<n;i++) {
			if (a[i].kind==1) {
				set(root,1,n,c[a[i].time],1);
			} else if (a[i].kind==2) {
				set(root,1,n,c[a[i].time],-1);
			} else {
				int tmp=get(root,1,n,c[a[i].time],1).first;
				if (tmp==-1) printf("-1\n");
				else {
					printf("%d\n",a[d[e[tmp]]].value);
				}
			}
			//print();
			//if (i%100==0) cerr<<cas<<' '<<i<<endl;
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值