luogu P4732 [BalticOI 2015] Editor / QOJ13034 Editor 题解
我们考虑用主席树维护操作是否活动的数组,如果活动那么值为它的级别。
当 \(a_i>0\) 时,我们直接把它插入到位置 \(i\) 上,并记录当前答案 \(ans_i\) 为 \(a_i\)。
当 \(a_i<0\) 时,我们找到当前最靠右的级别小于 \(-a_i\) 的位置 \(tmp\)(这个只需要维护区间最小值,并在线段树上二分即可),并把数组回溯到 \(tmp-1\) 时间的状态,也就是 \(tmp\) 这个操作未被执行的时候(为什么我们不需要保留 \(tmp\sim i\) 中的操作?我们并不是没有保留这些操作,而是这些操作已经被保留在以前的状态了。这些操作的级别 \(\ge-a_i\),即使后面的操作有能力把它们撤回,也只会先把 \(i\) 给撤回,回溯到 \(i-1\) 的状态,这些操作就又重新出现了),再把 \(-a_i\) 插入到 \(i\) 上,\(ans_i\) 设置为 \(ans_{tmp-1}\)。
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
const int inf=1e9;
int n,a[N],idx,mn[N<<5],lc[N<<5],rc[N<<5],rt[N],ans[N];
void pushup(int i){mn[i]=min(mn[lc[i]],mn[rc[i]]);}
int build(int tl,int tr){
int i=++idx;
if(tl==tr){
mn[i]=inf;
return i;
}
int tm=(tl+tr)>>1;
lc[i]=build(tl,tm);
rc[i]=build(tm+1,tr);
pushup(i);
return i;
}
int update(int pre,int tl,int tr,int p,int v){
int i=++idx;
lc[i]=lc[pre];rc[i]=rc[pre];
mn[i]=mn[pre];
if(tl==tr){
mn[i]=v;
return i;
}
int tm=(tl+tr)>>1;
if(p<=tm)lc[i]=update(lc[pre],tl,tm,p,v);
else rc[i]=update(rc[pre],tm+1,tr,p,v);
pushup(i);
return i;
}
int query(int i,int tl,int tr,int v){
if(tl==tr)return tl;
int tm=(tl+tr)>>1;
if(mn[rc[i]]<v)return query(rc[i],tm+1,tr,v);
return query(lc[i],tl,tm,v);
}
int main(){
// freopen("editor.in","r",stdin);
// freopen("editor.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
rt[0]=build(1,n);
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]>0){
rt[i]=update(rt[i-1],1,n,i,0);
ans[i]=a[i];
}else{
int tmp=query(rt[i-1],1,n,-a[i]);
rt[i]=update(rt[tmp-1],1,n,i,-a[i]);
ans[i]=ans[tmp-1];
}
cout<<ans[i]<<"\n";
}
return 0;
}

浙公网安备 33010602011771号