#离线,倒序,线段树#Comet OJ - Contest #15 E 栈的数据结构题

题目

初始时有 \(N\) 个空的栈,编号为 \(1 \sim N\),有以下三种类型的指令:

push \(L\) \(R\) \(v\):把编号 \(L \sim R\) 这连续 \(R-L+1\) 个栈都 push 一个数 \(v\)。

pop \(L\) \(R\):把编号 \(L \sim R\) 这连续 \(R-L+1\) 个栈都执行 pop 一次,保证进行此指令时,这 \(R-L+1\) 个栈都不为空。

find \(id\) \(pos\):询问第 \(id\) 个栈由栈顶数来第 \(pos\) 个数字是什么,保证进行此指令时,第 \(id\) 个栈至少有 \(pos\) 个数字。

输入会给你总共 \(Q\) 个指令,对于每个 find 指令请输出正确答案。

\(1 \le N, Q \le 2 \times 10^5\)


分析

正着模拟不好做,考虑倒着做,第\(pos\)个数字也就意味着在它之前的第\(pos\)次有效插入即为答案,
那么给每个询问设计倒计时,\(push\)和\(pop\)就转换成区间加问题,当整体最小值为0时记录该询问的答案


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=200011,inf=1e7;
struct rec{int x,y,z,w;}b[N],q[N];
int n,m,Q,ans[N],l[N],r[N],T,rk[N],w[N<<2],lazy[N<<2],p[N<<2];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(int ans){
    if (ans>9) print(ans/10);
	putchar(ans%10+48); 
}
inline signed min(int a,int b){return a<b?a:b;}
inline signed max(int a,int b){return a>b?a:b;}
bool cmp(int x,int y){return b[x].x<b[y].x;}
inline void build(int k,int l,int r){
	w[k]=inf;
	if (l==r) {p[k]=l; return;}
	rr int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	p[k]=w[k<<1]<w[k<<1|1]?p[k<<1]:p[k<<1|1];
}
inline void update(int k,int l,int r,int x,int y,int z){
	if (l==x&&r==y) {w[k]+=z,lazy[k]+=z; return;}
	rr int mid=(l+r)>>1;
	if (lazy[k]){
		lazy[k<<1]+=lazy[k],lazy[k<<1|1]+=lazy[k],
		w[k<<1]+=lazy[k],w[k<<1|1]+=lazy[k],lazy[k]=0;
	}
	if (y<=mid) update(k<<1,l,mid,x,y,z);
    else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
        else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
    p[k]=w[k<<1]<w[k<<1|1]?p[k<<1]:p[k<<1|1];
    w[k]=min(w[k<<1],w[k<<1|1]);
}
inline void upd(int k,int l,int r,int x,int y){
	if (l==r) {w[k]=y; return;}
	rr int mid=(l+r)>>1;
	if (lazy[k]){
		lazy[k<<1]+=lazy[k],lazy[k<<1|1]+=lazy[k],
		w[k<<1]+=lazy[k],w[k<<1|1]+=lazy[k],lazy[k]=0;
	}
	if (x<=mid) upd(k<<1,l,mid,x,y);
	    else upd(k<<1|1,mid+1,r,x,y);
	p[k]=w[k<<1]<w[k<<1|1]?p[k<<1]:p[k<<1|1];
    w[k]=min(w[k<<1],w[k<<1|1]);
}
signed main(){
	n=iut(),T=iut();
	for (rr int i=1;i<=T;++i){
		rr char c=getchar();
		while (!isalpha(c)) c=getchar();
		c=getchar();
		rr int x=iut(),y=iut();
		switch (c){
			case 'u':{
				q[++Q]=(rec){x,y,-1,iut()};
				break;
			}
			case 'o':{
				q[++Q]=(rec){x,y,1,-1};
				break;
			}
			case 'i':{
				++m,b[m]=(rec){x,y,0,Q};
				break;
			}
		}
	}
	for (rr int i=1;i<=m;++i) rk[i]=i;
	sort(rk+1,rk+1+m,cmp);
	for (rr int i=1;i<=m;++i) b[rk[i]].z=i;
	for (rr int i=1;i<=n;++i) l[i]=m+1;
	for (rr int i=1;i<=m;++i)
		l[b[rk[i]].x]=min(l[b[rk[i]].x],i),
		r[b[rk[i]].x]=max(r[b[rk[i]].x],i);
	for (rr int i=n;i>1;--i) l[i-1]=min(l[i-1],l[i]);
	for (rr int i=2;i<=n;++i) r[i]=max(r[i],r[i-1]);
	build(1,1,m);
	for (rr int i=Q,j=m;i;--i){
		for (;b[j].w==i;--j) upd(1,1,m,b[j].z,b[j].y);
		if (l[q[i].x]<=r[q[i].y]) update(1,1,m,l[q[i].x],r[q[i].y],q[i].z);
		while (!w[1]) ans[rk[p[1]]]=q[i].w,upd(1,1,m,p[1],inf);
	}
	for (rr int i=1;i<=m;++i) print(ans[i]),putchar(10);
	return 0;
}
上一篇:noip14


下一篇:线段树