题目链接
思路:这题曾经好像做过,但结果还是不会做。。。
其实观察一下假设,一、最后结果的最大值和最小值都在【li,ri】里,那么最大值减去最小值是同时变化的,二、如果最大值不在【li,ri】里的话,最后的结果也只会增不会减,所有我们枚举每个位置,假设最小值在这个位置,用线段树把以i为左端点的区间进行update,查询一下最大值减一下就行,不过这里要注意以下,查询完以后记得要把以i为右端点的区间的更新进行还原,如果不还原的话对于“二”假设来说最大值会减小,从而影响答案。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+1;
int a[maxn],u[maxn],v[maxn];
struct node{
int l,r,lazy,maxx;
}tree[maxn<<2];
vector<int>L[maxn],R[maxn],ans;
void pushup(int x)
{
tree[x].maxx=max(tree[x<<1].maxx,tree[x<<1|1].maxx);
}
void pushdown(int x)
{
if(tree[x].lazy)
{
tree[x<<1].maxx+=tree[x].lazy;
tree[x<<1|1].maxx+=tree[x].lazy;
tree[x<<1].lazy+=tree[x].lazy;
tree[x<<1|1].lazy+=tree[x].lazy;
tree[x].lazy=0;
}
}
void build(int x,int l,int r)
{
tree[x].l=l,tree[x].r=r;
if(l==r){
tree[x].maxx=a[l];return ;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
pushup(x);
}
void update(int x,int l,int r,int v)
{
if(l<=tree[x].l&&tree[x].r<=r)
{
tree[x].maxx+=v;
tree[x].lazy+=v;
return ;
}
pushdown(x);
int mid=(tree[x].l+tree[x].r)>>1;
if(l<=mid) update(x<<1,l,r,v);
if(mid<r) update(x<<1|1,l,r,v);
pushup(x);
}
int query(int x,int pos)
{
if(tree[x].l==tree[x].r) return tree[x].maxx;
pushdown(x);
int mid=(tree[x].l+tree[x].r)>>1;
if(pos<=mid) return query(x<<1,pos);
else return query(x<<1|1,pos);
pushup(x);
}
int main()
{
int n,m;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
build(1,1,n);
for(int i=1;i<=m;++i)
{
scanf("%d%d",&u[i],&v[i]);
L[u[i]].push_back(v[i]);
R[v[i]].push_back(u[i]);
}
int maxx=-0x3f3f3f3f,pos;
for(int i=1;i<=n;++i)
{
for(int j=0;j<L[i].size();++j)
update(1,i,L[i][j],-1);
int sum=tree[1].maxx-query(1,i);
if(maxx<sum) maxx=sum,pos=i;
for(int j=0;j<R[i].size();++j)
update(1,R[i][j],i,1);//进行还原
}
printf("%d\n",maxx);
for(int i=1;i<=m;++i)
if(u[i]<=pos&&pos<=v[i]) ans.push_back(i);
printf("%d\n",ans.size());
for(int i:ans) printf("%d ",i);
}