Codeforces Round #393 (Div. 2)(8VC Venture Cup Div. 2) E.Nikita and stack(线段树/后缀和+区间最值)

题目

有个小迷糊对栈进行了操作,

但他现在回想起来第p[i]次操作干了什么,是入栈还是出栈

特别地,如果对空栈pop,什么也不会发生

但是并不是按顺序回想起来的,

问按他回想的前i次对栈进行操作,栈顶的元素是什么

思路来源

https://www.cnblogs.com/quintessence/p/6392073.html

题解

本来是线段树维护后缀和,push对p[i]点+1,pop对p[i]点-1

然后找到第一个后缀和大于0的点就是答案

但是考虑到有些栈的操作是无效的,所以不能用线段树维护和

线段树维护区间和,每个点只代表自己的值

线段树维护最大值,每个点都代表一个后缀和,所以更新时就是一波区间修改

每个点都代表一个后缀和,就是每个点都不能影响其后面的点

所以每次修改p[i]的时候只能对[1,p[i]]的区间进行区间修改

注意到如果有pop操作无效,一定是pop在push前,

这样后来的push的区间修改会令自己这个点+1,先向右查询时并不影响答案

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
int m;
int pos,op,v;
int ans[maxn]; 
int dat[maxn*5],cov[maxn*5];
void pushup(int p)
{
	dat[p]=max(dat[p<<1],dat[p<<1|1]);
	//其实是维护这两段和是否大于0  
	//正+正>0,负+负<0 如果两段和>0一定是大正+小负 
}
void pushdown(int p,int l,int r)
{
	if(cov[p])
	{
		int mid=(l+r)/2;
		dat[p<<1]+=cov[p];
		dat[p<<1|1]+=cov[p]; 
		cov[p<<1]+=cov[p];
		cov[p<<1|1]+=cov[p];
		cov[p]=0;
	}
}
void update(int p,int l,int r,int ql,int qr,int v)
{
	if(ql<=l&&r<=qr)
	{
		dat[p]+=v;
		cov[p]+=v;
		return;
	}
	pushdown(p,l,r);
	int mid=(l+r)/2;
	if(ql<=mid)update(p<<1,l,mid,ql,qr,v);
	if(qr>mid)update(p<<1|1,mid+1,r,ql,qr,v); 
	pushup(p);
}
int ask(int p,int l,int r)
{
	if(l==r)return dat[p]>0?ans[l]:-1;
	pushdown(p,l,r);
	int mid=(l+r)/2;
	if(dat[p<<1|1]>0)return ask(p<<1|1,mid+1,r);
	if(dat[p<<1]>0)return ask(p<<1,l,mid);
	return -1;
}
int main()
{
	scanf("%d",&m);
	for(int i=1;i<=m;++i)
	{
		scanf("%d%d",&pos,&op);
		if(op)
		{
			scanf("%d",&v);
			ans[pos]=v;
			update(1,1,m,1,pos,1);
		}
		else update(1,1,m,1,pos,-1);
		printf("%d\n",ask(1,1,m));
	}
	return 0;
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值