传送门: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 ; }

Codeforces Round #535 (Div. 3) E2. Array and Segments (Hard version) 【区间更新 线段树】的更多相关文章

  1. CF #535 (Div. 3) E2 Array and Segments (Hard version) 利用线段树进行区间转移

    传送门 题意:    有m个区间,n个a[ i ] , 选择若干个区间,使得整个数组中的最大值和最小值的差值最小.n<=1e5,m<=300; 思路: 可以知道每个i,如果一个区间包含这个 ...

  2. CodeForces -Codeforces Round #496 (Div. 3) E2. Median on Segments (General Case Edition)

    参考:http://www.cnblogs.com/widsom/p/9290269.html 传送门:http://codeforces.com/contest/1005/problem/E2 题意 ...

  3. Codeforces Round #496 (Div. 3) E2 - Median on Segments (General Case Edition)

    E2 - Median on Segments (General Case Edition) 题目大意:给你一个数组,求以m为中位数的区间个数. 思路:很巧秒的转换,我们把<= m 数记为1, ...

  4. Codeforces Round #535 (Div. 3) 题解

    Codeforces Round #535 (Div. 3) 题目总链接:https://codeforces.com/contest/1108 太懒了啊~好久之前的我现在才更新,赶紧补上吧,不能漏掉 ...

  5. Codeforces Round #535 (Div. 3) [codeforces div3 难度测评]

    hhhh感觉我真的太久没有接触过OI了 大约是前天听到JK他们约着一起刷codeforces,假期里觉得有些颓废的我忽然也心血来潮来看看题目 今天看codeforces才知道居然有div3了,感觉应该 ...

  6. Codeforces Round #535 (Div. 3) 解题报告

    CF1108A. Two distinct points 做法:模拟 如果两者左端点重合就第二条的左端点++就好,然后输出左端点 #include <bits/stdc++.h> usin ...

  7. Codeforces Round #567 (Div. 2) E2 A Story of One Country (Hard)

    https://codeforces.com/contest/1181/problem/E2 想到了划分的方法跟题解一样,但是没理清楚复杂度,很难受. 看了题解觉得很有道理,还是自己太菜了. 然后直接 ...

  8. Codeforces Round #535(div 3) 简要题解

    Problem A. Two distinct points [题解] 显然 , 当l1不等于r2时 , (l1 , r2)是一组解 否则 , (l1 , l2)是一组合法的解 时间复杂度 : O(1 ...

  9. Codeforces Round #337 (Div. 2) D. Vika and Segments 线段树扫描线

    D. Vika and Segments 题目连接: http://www.codeforces.com/contest/610/problem/D Description Vika has an i ...

随机推荐

  1. 启停无线网卡bat脚本

    @echo off color 2 title 启停无线网卡 echo 启动无线网卡=======>按1键 echo 关闭无线网卡=======>按2键 set /p n= if /i & ...

  2. Expression Blend实例中文教程(8) - 动画设计快速入门StoryBoard

    上一篇,介绍了Silverlight动画设计基础知识,Silverlight动画是基于时间线的,对于动画的实现,其实也就是对对象属性的修改过程. 而Silverlight动画分类两种类型,From/T ...

  3. C#中引用类型和值类型的区别,分别有哪些

    C#的值类型包括:结构体(数值类型,bool型,用户定义的结构体),枚举,可空类型. C#的引用类型包括:数组,用户定义的类.接口.委托,object,字符串. 数组的元素,不管是引用类型还是值类型, ...

  4. 二:SpringAOP

    一:AOP 面向切面编程思想 横向重复,纵向抽取 |- filter中 |- 动态代理 |- interceptor中 二:动态代理 1.通过动态代理可以体现aop思想 2.对目标对象中的方法进行增强 ...

  5. redis(8)集群简介

    一.集群 互联网每天都会产生大量的数据,单实例已经不能满足需求.但是如果依赖于硬件成本的提升,那就不是所有人能够负担的起的. 集群这个时候出现,一定程度上解决了这个问题.它通过互联网,将多个单实例连接 ...

  6. Android-多线程和进程

    http://www.cnblogs.com/plokmju/p/android_ProcessOrThread.html 对于单线程模型,Android有两个规则: 不能阻塞UI线程 不能在工作线程 ...

  7. maven(5)--依赖特性

    依赖的子标签中有scope,常用值有compile.provide.test.runtime compile:编译范围有效,即编译和打包时都会将这个依赖存储 provide:编译测试有效,但是打包是将 ...

  8. JS里的居民们7-对象和数组转换

    编码 学习通用的数据用不同的数据结构进行存储,以及相互的转换 对象转为数组: var scoreObject = { "Tony": { "Math": 95, ...

  9. csharp:Learn how to post JSON string to generic Handler using jQuery in ASP.Net C#.

    /// <summary> ///參考: http://james.newtonking.com/json/help/index.html# /// 塗聚文(Geovin Du) 2014 ...

  10. java.io.FileNotFoundException

    1. 概述 上传图片到 o:/mmfiles_2017/39973/25444/333.jpg目录下 目录不存在会报标题中的错误 必须先创建目录 2. 方法 File filePath = new F ...