#离线,倒序,线段树#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;
}
标签:lazy,include,15,int,离线,pos,指令,个栈,倒序 来源: https://www.cnblogs.com/Spare-No-Effort/p/14979890.html