“科大讯飞杯”第十七届同济大学程序设计预选赛暨高校网络友谊赛 H时空栈 线段树

线段树维护区间加,区间最右边第一个小于x的数。

先说下正解:

开一个以时间为节点的线段树,每个节点维护的值为当前时间点栈内元素个数。

遇到入栈,让t,sz 的值加1,出栈:让t,sz的值减1.

碰到查询操作,先查询当前时间点的栈的元素个数nm,再查找[1,t]区间最右边的小于nm的时间点ans。

ans+1即最后一次入栈。(可以仔细想一下为什么)

上述操作用线段树处理即可。

区间加,单点查询。

和查询最右边小于x的数。

 

我刚开始的思路是二分+线段树,每个节点维护的是每个时间点的操作,入栈为1,出栈为-1.查询时肯定是查询区间[1,t]中

的一个区间[m,t]使得m最大,且区间和刚好大于等于1.于是用二分+区间查询。但这是错的!

为什么?因为区间和不满足二分性质。。

 

下面是AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 2e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
*/

struct node{
	int op,t,x;
}p[M];
int mn[M<<2],li[M],a[M],tg[M<<2];
void pu(int o,int l,int r)
{
	if(!tg[o])return ;
	tg[ls]+=tg[o];tg[rs]+=tg[o];
	mn[ls]+=tg[o];mn[rs]+=tg[o];
	tg[o]=0;
}
void up(int o,int l,int r,int x,int y,int d)
{
	if(x<=l&&r<=y)
	{
		mn[o]+=d;
		tg[o]+=d;
		return ;
	}
	pu(o,l,r);
	int m=(l+r)/2;
	if(x<=m)up(ls,l,m,x,y,d);
	if(y>m) up(rs,m+1,r,x,y,d);
	mn[o]=min(mn[ls],mn[rs]);
}
bool f;
int tmp,ans;
int qu(int o,int l,int r,int x)//单点查询x的值
{
	if(l==r)
		return mn[o];
	int m=(l+r)/2;
	pu(o,l,r);
	if(x<=m)return qu(ls,l,m,x);
	return qu(rs,m+1,r,x);
} 
void qu(int o,int l,int r,int x,int y,int nm)//区间l,r  最右边的,值小于tmp的  返回ans 
{
	if(r<x||l>y||f)return ;
	if(l==r)
	{
		ans=l;
		if(mn[o]<nm)f=true;
		return;
	}
	pu(o,l,r);
	int m=(l+r)/2;
	if(mn[rs]<nm)qu(rs,m+1,r,x,y,nm);
	qu(ls,l,m,x,y,nm);
}
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int n,sz=0;
  	cin>>n;
  	for(int i=1;i<=n;i++)
  	{
  		cin>>p[i].op;
  		if(p[i].op==0)cin>>p[i].t>>p[i].x;
		else cin>>p[i].t;
		li[++sz]=p[i].t;
	}
	sort(li+1,li+1+sz);
	for(int i=1;i<=n;i++)
	{
		p[i].t=lower_bound(li+1,li+1+sz,p[i].t)-li;
		if(p[i].op==2)
		{
			int nm=qu(1,1,sz,p[i].t);//这个时刻栈中有多少元素
			f=false;
			qu(1,1,sz,1,p[i].t,nm); 
			if(!f)ans=0;
			cout<<a[ans+1]<<endl;
		}
		else 
		{
			if(p[i].op==0)
				up(1,1,sz,p[i].t,sz,1),a[p[i].t]=p[i].x;
			else up(1,1,sz,p[i].t,sz,-1);
		}
	}
	return 0;
}
/*
8
0 6 2
2 7
0 3 3
1 5
0 1 1
2 4
2 8
2 2

*/

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值