- 题目链接:http://codeforces.com/contest/1108/problem/E2-
- 题意:给你一个大小为n(1<=n<=1e5) 的数组a,给你m(m<=300)个区间 [l, r],你可以选择m个区间中的任意个区间,每个区间会使a中对应位置的数减一。问如何选择区间让数组a中的最大值和最小值的差值最大。
- 思路:在选择完区间后,最终结果中的a中显然必然存在最小值和最大值,而对于最小值,必然有:所有包含最小值的区间都被选择了。可以这样证明:
- 如果某个区间不包含最终最大值(最终结果中的最大值),而包含最终最小值(最终结果中的最小值),那么显然选择这个区间可以让差值趋向最大。
- 如果某个区间不包含最终最大值,也不包含最终最小值,那么选不选择这个区间都没有影响。
- 如果某个区间既包含最终最大值,也包含最终最小值,那么选不选择这个区间都没影响。
- 那么只要选择包含最终最小值的所有区间,就能保证差值最大。通过遍历a中的每个元素,对于每个元素,假设其为最终最小值,选择包含其的所有区间并执行减一操作,然后找出整个a中的最大值和最小值的差值。这样就能找出最大差值。
- 注意:遍历a时,到达某区间左端点时,将该区间的对应a[i]加一,离开某区间右端点
后将该区间对应a[i]减一。否则会TLE。另外求最大最小值可以用线段数降低时间复杂度。
#include <bits/stdc++.h>
#define pi acos(-1)
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int INF = 0x3f3f3f3f;
const LL ll_INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 1e5 + 10;
const int mod = 1e9 + 7;
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
LL maxx[maxn<<2], add[maxn<<2];
LL minn[maxn<<2];
LL a[maxn];
vector<int> in[maxn], out[maxn], usd;
PII p[310];
void PushUp(int rt)
{
maxx[rt] = max(maxx[rt<<1], maxx[rt<<1|1]);
minn[rt] = min(minn[rt<<1], minn[rt<<1|1]);
}
void PushDown(int rt, int ln, int rn) {
if(add[rt]){
add[rt<<1] += add[rt];
add[rt<<1|1] += add[rt];
maxx[rt<<1] += add[rt];
maxx[rt<<1|1] += add[rt];
minn[rt<<1] += add[rt];
minn[rt<<1|1] += add[rt];
add[rt]=0;
}
}
void Build(int l, int r, int rt) {
if(l==r){
maxx[rt]=a[l];
minn[rt]=a[l];
return;
}
int mid = (l+r)>>1;
Build(l, mid, rt<<1);
Build(mid+1, r, rt<<1|1);
PushUp(rt);
}
void update(int L, int R, LL C, int l, int r, int rt) {
if(L<=l && r<=R){
maxx[rt]+=C;
minn[rt]+=C;
add[rt]+=C;
return ;
}
int mid = (l+r)>>1;
PushDown(rt, mid-l+1, r-mid);
if(L <= mid) update(L, R, C, l, mid, rt<<1);
if(R > mid) update(L, R, C, mid+1, r, rt<<1|1);
PushUp(rt);
}
PLL Query(int L, int R, int l, int r, int rt) {
if(L<=l && r<=R){
return PLL(maxx[rt], minn[rt]);
}
int mid = (l+r)>>1;
PushDown(rt, mid-l+1, r-mid);
LL big = 0, small = 0;
PLL lpart = Query(L, R, l, mid, rt<<1);
PLL rpart = Query(L, R, l, mid+1, rt<<1|1);
big = max(lpart.first, rpart.first);
small = min(lpart.second, rpart.second);
return PLL(big, small);
}
void change(int l, int r, int num)
{
for(int i=l; i<=r; i++) a[i]+=num;
}
int main() {
fastio;
int n, m;
cin >> n >> m;
for(int i=1; i<=n; i++){
cin >> a[i];
}
Build(1, n, 1);
for(int i=1; i<=m; i++){
int l,r;
cin >> l >> r;
p[i].first = l;
p[i].second = r;
in[l].push_back(i);
out[r+1].push_back(i);
}
LL ansmax = a[1], ansmin = a[1], ansd=0, ansp=0;
for(int i=2; i<=n; i++){
ansmax = max(ansmax, a[i]);
ansmin = min(ansmin, a[i]);
}
ansd = ansmax - ansmin;
for(int i=1; i<=n; i++){
for(int j=0; j<(int)in[i].size(); j++){
int idx = in[i][j];
update(p[idx].first, p[idx].second, -1, 1, n, 1);
}
for(int j=0; j<(int)out[i].size(); j++){
int idx = out[i][j];
update(p[idx].first, p[idx].second, 1, 1, n, 1);
}
if(!in[i].empty() || !out[i].empty()){
ansmax = a[1];
ansmin = a[1];
PLL ansm = Query(1, n, 1, n, 1);
ansmax = ansm.first;
ansmin = ansm.second;
if(ansmax - ansmin >= ansd){
ansd = ansmax - ansmin;
ansp = i;
}
}
}
cout << ansd << endl;
for(int i=1; i<=m; i++){
if(p[i].first <= ansp && ansp <= p[i].second) usd.push_back(i);
}
cout << (int)usd.size() << endl;
for(int i=0; i<(int)usd.size(); i++){
cout << usd[i];
if(i == (int)usd.size() - 1) cout <<'\n';
else cout << ' ';
}
}