传送门:http://codeforces.com/contest/1108/problem/E2

E2. Array and Segments (Hard version)
time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

The only difference between easy and hard versions is a number of elements in the array.

You are given an array aa consisting of nn integers. The value of the ii-th element of the array is aiai.

You are also given a set of mm segments. The jj-th segment is [lj;rj][lj;rj], where 1≤lj≤rj≤n1≤lj≤rj≤n.

You can choose some subset of the given set of segments and decrease values on each of the chosen segments by one (independently). For example, if the initial array a=[0,0,0,0,0]a=[0,0,0,0,0] and the given segments are [1;3][1;3] and [2;4][2;4] then you can choose both of them and the array will become b=[−1,−2,−2,−1,0]b=[−1,−2,−2,−1,0].

You have to choose some subset of the given segments (each segment can be chosen at most once) in such a way that if you apply this subset of segments to the array aa and obtain the array bb then the value maxi=1nbi−mini=1nbimaxi=1nbi−mini=1nbiwill be maximum possible.

Note that you can choose the empty set.

If there are multiple answers, you can print any.

If you are Python programmer, consider using PyPy instead of Python when you submit your code.

Input

The first line of the input contains two integers nn and mm (1≤n≤105,0≤m≤3001≤n≤105,0≤m≤300) — the length of the array aaand the number of segments, respectively.

The second line of the input contains nn integers a1,a2,…,ana1,a2,…,an (−106≤ai≤106−106≤ai≤106), where aiai is the value of the ii-th element of the array aa.

The next mm lines are contain two integers each. The jj-th of them contains two integers ljlj and rjrj (1≤lj≤rj≤n1≤lj≤rj≤n), where ljlj and rjrj are the ends of the jj-th segment.

Output

In the first line of the output print one integer dd — the maximum possible value maxi=1nbi−mini=1nbimaxi=1nbi−mini=1nbi if bb is the array obtained by applying some subset of the given segments to the array aa.

In the second line of the output print one integer qq (0≤q≤m0≤q≤m) — the number of segments you apply.

In the third line print qq distinct integers c1,c2,…,cqc1,c2,…,cq in any order (1≤ck≤m1≤ck≤m) — indices of segments you apply to the array aa in such a way that the value maxi=1nbi−mini=1nbimaxi=1nbi−mini=1nbi of the obtained array bb is maximum possible.

If there are multiple answers, you can print any.

Examples
input

Copy
5 4
2 -2 3 1 2
1 3
4 5
2 5
1 3
output

Copy
6
2
4 1
input

Copy
5 4
2 -2 3 1 4
3 5
3 4
2 4
2 5
output

Copy
7
2
3 2
input

Copy
1 0
1000000
output

Copy
0
0
Note

In the first example the obtained array bb will be [0,−4,1,1,2][0,−4,1,1,2] so the answer is 66.

In the second example the obtained array bb will be [2,−3,1,−1,4][2,−3,1,−1,4] so the answer is 77.

In the third example you cannot do anything so the answer is 00.

题意概括:

给出一段长度为 N 的初始序列,以及 M 个区间,要求选择若干区间(选择该区间则对该区间的数进行 -1 操作),使得序列中的最大值和最小值的差值最大。

解题思路:

选择区间的三种情况:

(1)该区间只包含最后的最小值,则选择该区间会优化最大差值,必选。

(2)该区间包含最后的最小值和最大值,对差值无影响,选不选无所谓。

(3)该区间未包含最后的最小值,有可能会减小最大差值,不可选。

但是我们并不知道最后的最小值是哪个?所以需要枚举一遍,假设每个值都有可能成为最后的最小值,最后取最优的解。

既然假设了当前的这位数为会成为最后的最小值,那么根据上面三种区间的选取情况,我们要选择相对应的区间,这样才能达到目前这一位作为最小值的最优解。

如果每到一位都暴力一遍所有区间,这样复杂度太大了,我们可以用一个 Left [ k ] 动态链表 和一个 Right [ k ] 动态链表,分别记录以 k 位开始的区间有哪些和以 k 位结束的区间有哪些?

这样更新的时候只需要操作这些与当前位相关的区间即可。

这里的区间更新有两种方案:

(1)直接暴力更新

 AC code:

  

 #include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<set>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const LL MOD = 1e9+;
const int MAXN = 1e5+;
const int MAXM = ;
vector<int>Le[MAXN];
vector<int>Ri[MAXN];
int num[MAXN];
int ans_q[MAXM];
int N, M;
struct data
{
int l, r;
}q[MAXM]; void update(int L, int R, int v)
{
for(int i = L; i <= R; i++){
num[i]+=v;
}
} int main()
{
int index;
int maxx = -INF, minn = INF;
scanf("%d %d", &N, &M);
for(int i = ; i <= N; i++){
scanf("%d", &num[i]);
maxx = max(maxx, num[i]);
if(minn > num[i]){minn = num[i]; index = i;}
} for(int i = ; i <= M; i++){
scanf("%d %d", &q[i].l, &q[i].r);
Le[q[i].l].push_back(i);
Ri[q[i].r+].push_back(i);
} int ans = maxx-minn;
int tp;
for(int i = ; i <= N; i++){
for(int ed = ; ed < Ri[i].size(); ed++){
tp = Ri[i][ed];
update(q[tp].l, q[tp].r, );
} for(int st = ; st < Le[i].size(); st++){
tp = Le[i][st];
update(q[tp].l, q[tp].r, -);
} if(!Le[i].empty() || !Ri[i].empty()){
maxx = -INF;minn = INF;
for(int i = ; i <= N; i++){
maxx = max(maxx, num[i]);
minn = min(minn, num[i]);
}
if(ans < maxx-minn){
ans = maxx-minn;
index = i;
}
}
}
if(ans <= -INF){
puts("");
puts("");
}
else{
printf("%d\n", ans);
int cnt = ;
for(int i = ; i <= M; i++){
if(q[i].l <= index && q[i].r >= index){
ans_q[++cnt] = i;
}
}
printf("%d\n", cnt);
for(int i = ; i <= cnt; i++){
printf("%d ", ans_q[i]);
}
puts("");
}
return ;
}

(2)可持续化线段树的区间更新(即 lazy tag)

  AC code:

  

 ////可持久化线段树优化的区间更新
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int MAXN = 1e5+;
const int MAXM = ; int N, M;
int a[MAXN], L[MAXM], R[MAXM], ans[MAXN];
vector<int>add[MAXN], sub[MAXN]; struct node
{
int l, r;
int maxx, minn, lazy;
}tree[MAXN<<]; void push_up(int k)
{
tree[k].maxx = max(tree[k<<].maxx, tree[k<<|].maxx);
tree[k].minn = min(tree[k<<].minn, tree[k<<|].minn);
} void push_down(int k)
{
if(tree[k].l != tree[k].r){
tree[k<<].maxx += tree[k].lazy; tree[k<<].minn += tree[k].lazy;
tree[k<<|].maxx+=tree[k].lazy; tree[k<<|].minn+=tree[k].lazy;
tree[k<<].lazy += tree[k].lazy;
tree[k<<|].lazy += tree[k].lazy;
}
tree[k].lazy = ;
} void build(int k, int l, int r)
{
tree[k].l = l;
tree[k].r = r;
if(l == r){
tree[k].maxx = a[l];
tree[k].minn = a[l];
tree[k].lazy = ;
return;
}
int mid = (l+r)>>;
build(k<<, l, mid);
build(k<<|, mid+, r);
push_up(k);
} void update(int k, int l, int r, int x)
{
if(tree[k].lazy) push_down(k);
tree[k].maxx+=x;
tree[k].minn+=x;
if(tree[k].l == l && tree[k].r == r){
tree[k].lazy += x;
return;
}
int mid = (tree[k].l + tree[k].r)>>;
if(r <= mid){
update(k<<, l, r, x);
}
else if(l > mid){
update(k<<|, l, r, x);
}
else{
update(k<<, l, mid, x);
update(k<<|, mid+, r, x);
}
push_up(k);
} int query_max(int k, int l, int r)
{
int maxx;
if(tree[k].lazy) push_down(k);
if(tree[k].l == l && tree[k].r == r) return tree[k].maxx;
int mid = (tree[k].l + tree[k].r)>>;
if(r <= mid) maxx = query_max(k<<, l, r);
else if(l > mid) maxx = query_max(k<<|, l, r);
else{
maxx = max(query_max(k<<, l, mid), query_max(k<<|, mid+, r));
}
return maxx;
} int query_min(int k, int l, int r)
{
int minn;
if(tree[k].lazy) push_down(k);
if(tree[k].l == l && tree[k].r == r) return tree[k].minn;
int mid = (tree[k].l + tree[k].r)>>;
if(r <= mid) minn = query_min(k<<, l, r);
else if(l > mid) minn = query_min(k<<|, l, r);
else
minn = min(query_min(k<<, l, mid), query_min(k<<|, mid+, r));
return minn;
} int main()
{
scanf("%d %d", &N, &M);
for(int i = ; i <= N; i++) scanf("%d", &a[i]); for(int i = ; i <= M; i++){
scanf("%d%d", &L[i], &R[i]); sub[ L[i] ].push_back(i);
add[ R[i] ].push_back(i);
} build(, , N); int d = -, p;
for(int i = ; i <= N; i++){ for(int j = ; j < add[i-].size(); j++){
int id = add[i-][j];
update(, L[id], R[id], );
} for(int j = ; j < sub[i].size(); j++){
int id = sub[i][j];
update(, L[id], R[id], -);
} int det = query_max(, , N) - query_min(, , N);
//printf("det:%d\n", det);
if(det > d){
d = det;
p = i;
}
} printf("%d\n", d);
int t = ;
for(int i = ; i <= M; i++){
if(L[i] <= p && p <= R[i])
ans[t++] = i;
} printf("%d\n", t);
for(int i = ; i < t; i++){
printf("%d ", ans[i]);
}
puts(""); return ; }

最新文章

  1. Hibernate criteria 增加排序项
  2. ASP.NET Web API 使用Swagger生成在线帮助测试文档
  3. ORCLE数据库导出导入
  4. [实战经验]Macbook pro 苹果系统换window系统
  5. 经典SQL语句大全之提升
  6. [转] Node.js 服务端实践之 GraphQL 初探
  7. A5营销访谈:卢松松和你聊新媒体运营那些事
  8. 浙江大学Pat 1036 题解
  9. 遇到looper之类关于消息循环的
  10. oracle中查询用户信息
  11. Android嵌套滑动不流畅记录随笔
  12. nginx日志文件的定时切割与归纳
  13. C#子类重写父类函数的两种方法
  14. linux 锁定重要文件 更改重要命令
  15. ORA-00911: invalid character 包含中文报错
  16. [Algorithm] Binary tree: Level Order Traversal
  17. 设计模式之代理模式(Proxy Pattern)_远程代理解析
  18. Ubuntu下gcc的简单使用
  19. 使用Python进行分布式系统协调 (ZooKeeper/Consul/etcd)
  20. 10个重要的算法C语言实现源代码

热门文章

  1. win10-查看wifi密码
  2. YII2使用gii
  3. Silverlight &amp; Blend动画设计系列五:故事板(StoryBoards)和动画(Animations)
  4. Spring学习笔记:jdbcTemplate和数据源配置
  5. 流畅的python和cookbook学习笔记(九)
  6. zookeeper学习实践1-实现分布式锁
  7. 【转】js判断一个object对象是否为空
  8. express的proxy实现前后端分离
  9. 谈谈HTML5中的history.pushSate方法,弥补ajax导致浏览器前进后退无效的问题
  10. vscode 快速生成html