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;
}

浙公网安备 33010602011771号