luogu P4732 [BalticOI 2015] Editor / QOJ13034 Editor 题解

link1 link2

我们考虑用主席树维护操作是否活动的数组,如果活动那么值为它的级别。
\(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;
}
posted @ 2026-09-03 09:10  cqbzcjh  阅读(3)  评论(0)    收藏  举报