http://codeforces.com/contest/1108/problem/E2
题意:
给你一个长度为n的序列,m个区间,你可以选择若干的区间,对区间内所有数-1。然后设x为修改后的数组中最大元素-最小元素的大小,求最大的x。以及让你给出一个实现的方案,即需要选择几个区间,选择哪些区间。任意输出一种方案即可。
题解:
简要:
枚举每个点,把包含这个点的所有边加上,把之前加了但是现在不包含这个点的边删除,直接上线段树维护就可以了。
详细:
在E1中,我们可以通过这个题中优美的性质,对于每一个区间ai,通过枚举在这个区间的以及不在这个区间的两个点,我们就可以用O(n^2m)的时间复杂度进行求解。
但是在这个题中,n的范围在10^5,因此我们需要用一些数据结构进行优化。
我们考虑这几种情况,对于每一个区间操作,如果区间内的最小值恰好在要更新的区间内,而最大值不在,则此时答案必定更优;如果最小值和最大值恰在要更新的区间内,则答案不变;如果最大值在而最小值不在,则答案必定更差。
至此,我们可以发现,要使得答案不会变差,当且仅当最小值恰好在要更新的区间内。
但是我们目前并不知道哪一个点作为最小值点更优,因此我们可以枚举最小值点的位置pos。根据我们之前的分析,最小值点能够防止答案变差,因此那些能够把我们所枚举的pos包含的区间必定要更新。而一个区间要包含一个点,则这个区间至少是那些以该点为起始点的区间。因此我们只需要在枚举最小值点位置的过程中,不断的进行区间−1即可。
而我们需要注意的是,在我们枚举的过程中,倘若我们之前更新的某一个区间不能包含当前的位置,我们需要把之前的影响消去,否则会导致将区间的最大值也减1,导致答案不正确。因此,我们只需要在之前枚举的过程的最后,把以当前位置pos为结尾的所有区间的影响消去即可。
因为存在区间更新以及区间求最大值,因此我们可以用线段树进行维护。
总的时间复杂度为O(nlogn)
code:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
int a[100004];
struct line{
int l,r,id;
bool friend operator < (line a ,line b){
if(a.l==b.l)return a.r<b.r;
else return a.l<b.l;
}
}l[304],r[304];
struct node{
int l,r,w,laz;
}t[400004];
void build(int rt,int l,int r){
t[rt]={l,r,0,0};
if(l==r)t[rt].w=a[l];
else {
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
t[rt].w=max(t[rt<<1].w,t[rt<<1|1].w);
}
}
void pushdown(int rt){
if(t[rt].laz==0)return ;
t[rt<<1].laz+=t[rt].laz;
t[rt<<1|1].laz+=t[rt].laz;
t[rt<<1].w+=t[rt].laz;
t[rt<<1|1].w+=t[rt].laz;
t[rt].laz=0;
}
void update(int rt,int l,int r,int w){
if(t[rt].l>=l&&t[rt].r<=r){
t[rt].laz+=w;
t[rt].w+=w;
} else{
pushdown(rt);
int mid=(t[rt].l+t[rt].r)>>1;
if(l<=mid)update(rt<<1,l,r,w);
if(r>mid)update(rt<<1|1,l,r,w);
t[rt].w=max(t[rt<<1].w,t[rt<<1|1].w);
}
}
int main(){
int n,m;
cin>>n>>m;
for (int i = 1; i <= n; ++i) {
scanf("%d",&a[i]);
}
for (int i = 1; i <=m ; ++i) {
scanf("%d%d",&l[i].l,&l[i].r);
l[i].id=i;
r[i]=l[i];
}
sort(l+1,l+1+m);
build(1,1,n);
int cnt1=1,cnt2=1;
int ans=-1000000000;
vector<int>v;
vector<int>ansv;
for (int i = 1; i <= n; ++i) {
//这里加区间删区间可以用优先队列优化
while(cnt2<=m&&l[cnt2].l<=i){
update(1,l[cnt2].l,l[cnt2].r,-1);
v.push_back(l[cnt2].id);
cnt2++;
}
for (int j = 0; j < v.size(); ++j) {
if(r[v[j]].r<i){
update(1,r[v[j]].l,r[v[j]].r,1);
v.erase(v.begin()+j);
j--;
}
}
if(ans<t[1].w-a[i]+(int)v.size()){
ans=t[1].w-a[i]+(int)v.size();
ansv=v;
}
}
if(ans==-1000000000){
puts("0");
puts("0");
return 0;
}
printf("%d\n",ans);printf("%d\n",ansv.size());
if(ansv.size()>0){
for (int i = 0; i < ansv.size(); ++i){
printf("%d ",ansv[i]);
}
}
}