Codeforces 722C Destroying Array 题解 [ 黄 ] [ 延迟删除堆 ] [ 并查集 ] [ 倒序操作 ]

Destroying Array:介绍一种延迟删除堆的技巧。

Sol.1 倒序枚举

因为只有分裂操作,所以倒序枚举之后就可以转化为合并操作,用并查集维护最大值即可。

时间复杂度 \(O(n)\)

Sol.2 延迟删除堆

考虑直接做分裂操作,每次找到分裂出的两个区间,丢到第一个大根堆里;然后把删除的数所处的原区间丢到第二个大根堆里,代表把这个元素从第一个大根堆中删掉

每次查询的时候,在两堆不空把相同的堆顶丢掉即可。因为要删的已经在堆顶删完了,没删的因为只要求最大值,删和没删是等效的。这叫做延迟删除堆

查询左右端点可以用 set 维护已经删除的点。注意细节问题。

时间复杂度 \(O(n\log n)\)

#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
const int N=100005;
priority_queue<ll>q1,q2;
ll n,a[N],f[N];
set<int>pos;
int main()
{
    //freopen("sample.in","r",stdin);
    //freopen("sample.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        f[i]=f[i-1]+a[i];
    }
    q1.push(f[n]);
    q1.push(0);
    pos.insert(0);
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        auto it=pos.lower_bound(x);
        int r;
        if(it!=pos.end())r=(*it)-1;
        else r=n;
        if(r!=x)q1.push(f[r]-f[x]);
        int l;
        if(it!=pos.begin())
        {
            --it;
            l=(*it)+1;
        }
        else l=1;
        if(l!=x)q1.push(f[x-1]-f[l-1]);
        q2.push(f[r]-f[l-1]);
        while(!q2.empty()&&!q1.empty()&&q1.top()==q2.top())
        {
            q1.pop();
            q2.pop();
        }
        cout<<q1.top()<<'\n';
        pos.insert(x);
    }
    return 0;
}
posted @ 2025-06-15 21:06  KS_Fszha  阅读(16)  评论(0)    收藏  举报