CF1108E2 Array and Segments (Hard version)
思路
怎么会有题解是 \(O(n^2+nm)\) 的垃圾做法阿,这题可以直接线段树做。
考虑枚举一个点 \(i\),假如我们想要 \(i\) 点作为最小值,贪心地想,我们如果把所有包含 \(i\) 的区间选进去,那么结果一定不劣。
假设最大值位于点 \(j\),区间 \(k\) 包含了区间 \(i\)。
那么我们可以分类讨论:
- 区间 \(k\) 包含了点 \(j\),此时 \(a_i,a_j\) 一起减,答案不变。
- 区间 \(k\) 未包含点 \(j\),此时仅有 \(a_i\) 会减,答案增大 \(1\)。
总上所述,最有策略是选择所有包含点 \(i\) 的区间。
于是仅需一颗支持区间修改的线段树即可。
时间复杂度 \(O(n \log n+m \log n)\)。
代码
#include<bits/stdc++.h>
using namespace std;
int const N=1e5+10;
struct Segment_Tree{
#define ls (x<<1)
#define rs (x<<1|1)
#define mid ((l+r)>>1)
int minx[N<<2],maxx[N<<2],lazy[N<<2];
inline void pushdown(int x){
minx[ls]+=lazy[x];minx[rs]+=lazy[x];
maxx[ls]+=lazy[x];maxx[rs]+=lazy[x];
lazy[ls]+=lazy[x];lazy[rs]+=lazy[x];
lazy[x]=0;
}
inline void update(int x,int l,int r,int ll,int rr,int v){
if (ll<=l && r<=rr){minx[x]+=v,maxx[x]+=v,lazy[x]+=v;return;}
pushdown(x);
if (ll<=mid) update(ls,l,mid,ll,rr,v);
if (mid<rr) update(rs,mid+1,r,ll,rr,v);
minx[x]=min(minx[ls],minx[rs]);
maxx[x]=max(maxx[ls],maxx[rs]);
}
}T;
int a[N],xx[N],yy[N];
vector<int>b[N];
priority_queue< pair<int,int>,deque< pair<int,int> >,greater< pair<int,int> > >q;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int n,m;cin>>n>>m;int x,y,ans=0,pl=0;
for (int i=1;i<=n;++i) cin>>a[i],T.update(1,1,n,i,i,a[i]);
for (int i=1;i<=m;++i) cin>>x>>y,b[x].push_back(y),xx[i]=x,yy[i]=y;
for (int i=1;i<=n;++i){
for (auto j:b[i]) T.update(1,1,n,i,j,-1),q.push({j,i});
while (!q.empty() && q.top().first<i) T.update(1,1,n,q.top().second,q.top().first,1),q.pop();
if (T.maxx[1]-T.minx[1]>ans) ans=T.maxx[1]-T.minx[1],pl=i;
}
cout<<ans<<'\n';
vector<int>Ans;
for (int i=1;i<=m;++i)
if (xx[i]<=pl && yy[i]>=pl) Ans.push_back(i);
cout<<(int)Ans.size()<<'\n';
for (auto i:Ans) cout<<i<<' ';
cout<<'\n';
return 0;
}

浙公网安备 33010602011771号