Codeforces 1108E2

E2. Array and Segments (Hard version)

Description:

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

You are given an array \(a\) consisting of \(n\) integers. The value of the \(i\)-th element of the array is \(a_i\).

You are also given a set of \(m\) segments. The \(j\)-th segment is \([l_j; r_j]\), where \(1 \le l_j \le r_j \le 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]\) and the given segments are \([1; 3]\) and \([2; 4]\) then you can choose both of them and the array will become \(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 \(a\) and obtain the array \(b\) then the value \(\max\limits_{i=1}^{n}b_i - \min\limits_{i=1}^{n}b_i\) will 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 \(n\) and \(m\) (\(1 \le n \le 10^5, 0 \le m \le 300\)) — the length of the array \(a\) and the number of segments, respectively.

The second line of the input contains \(n\) integers \(a_1, a_2, \dots, a_n\) (\(-10^6 \le a_i \le 10^6\)), where \(a_i\) is the value of the \(i\)-th element of the array \(a\).

The next \(m\) lines are contain two integers each. The \(j\)-th of them contains two integers \(l_j\) and \(r_j\) (\(1 \le l_j \le r_j \le n\)), where \(l_j\) and \(r_j\) are the ends of the \(j\)-th segment.

Output

In the first line of the output print one integer \(d\) — the maximum possible value \(\max\limits_{i=1}^{n}b_i - \min\limits_{i=1}^{n}b_i\) if \(b\) is the array obtained by applying some subset of the given segments to the array \(a\).

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

In the third line print \(q\) distinct integers \(c_1, c_2, \dots, c_q\) in any order (\(1 \le c_k \le m\)) — indices of segments you apply to the array \(a\) in such a way that the value \(\max\limits_{i=1}^{n}b_i - \min\limits_{i=1}^{n}b_i\) of the obtained array \(b\) is maximum possible.

If there are multiple answers, you can print any.

Sample Input:

5 4

2 -2 3 1 2

1 3

4 5

2 5

1 3

Sample Output:

6

2

4 1

Sample Input:

5 4

2 -2 3 1 4

3 5

3 4

2 4

2 5

Sample Output:

7

2

3 2

Sample Input:

1 0

1000000

Sample Output:

0

0

题目链接

题解:

有一个长为\(n\)的数列,有\(m\)个线段,每个线段将该线段区间的所有数减一,你可以选任意个线段,要求最大化极差并输出一种方案

这种极差的题一个套路是固定最大值求最小值

那么我们可以枚举每一个数作为最大值的方案,对不包含这个数的线段进行操作,然后找最大最小值即可,利用差分的思想单次操作可以\(O(1)\),最后查询极值\(O(n)\),这样我们就找到了一个\(O(n^2)\)的优秀算法,可以通过这题的简单版本

然后我们注意到线段数很少,只有\(300\)个,那么我们可以将原数列分为至多\(600\)段,每一段的数作为最大值时策略是相同的,我们就的到了\(O(n \cdot m +m^2)\)的算法,cf机子上跑得飞快

另外,可以用线段树加速操作得到\(O(mlog(n))\)的做法

甚至可以将\(n\)也变成\(m\),因为我们只关心每一段的极值,可以把原数列切成至多\(600\)段,每一段记录最大最小值即可,复杂度为\(O(m^2)\), 不知道为什么评论指出这个算法的老哥的代码跑的还没我\(O(n \cdot m + m^2)\)快...

AC代码:

#include <bits/stdc++.h>
using namespace std; const int N = 1e5 + 10, M = 310; int n, a[N], b[N], ans, l[M], r[M], m, rec, cnt;
set<int> key; int main() {
scanf("%d%d", &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], &r[i]);
key.insert(l[i]);
key.insert(r[i] + 1);
}
ans = *max_element(a + 1, a + n + 1) - *min_element(a + 1, a + n + 1);
for(auto it = key.begin(); it != key.end(); ++it) {
int i = *it; ++cnt;
memset(b, 0, sizeof(b));
int mx = -1e9, mn = 1e9, sum = 0;
for(int j = 1; j <= m; ++j) {
if(l[j] <= i && i <= r[j]) continue;
b[l[j]]--, b[r[j] + 1]++;
}
for(int j = 1; j <= n; ++j) {
sum += b[j];
mx = max(mx, a[j] + sum);
mn = min(mn, a[j] + sum);
}
if(mx - mn > ans) {
rec = i;
ans = mx - mn;
}
}
printf("%d\n", ans);
if(rec) {
vector<int> res;
for(int i = 1; i <= m; ++i) {
if(l[i] <= rec && rec <= r[i]) continue;
res.push_back(i);
}
printf("%d\n", (int)res.size());
for(int i = 0; i < res.size(); ++i)
printf("%d%c", res[i], " \n"[i == res.size() - 1]);
}
else
puts("0\n");
return 0;
}

Codeforces 1108E2 Array and Segments (Hard version) 差分, 暴力的更多相关文章

  1. Codeforces 1108E2 Array and Segments (Hard version)(差分+思维)

    题目链接:Array and Segments (Hard version) 题意:给定一个长度为n的序列,m个区间,从m个区间内选择一些区间内的数都减一,使得整个序列的最大值减最小值最大. 题解:利 ...

  2. codeforces#1108E2. Array and Segments (线段树+扫描线)

    题目链接: http://codeforces.com/contest/1108/problem/E2 题意: 给出$n$个数和$m$个操作 每个操作是下标为$l$到$r$的数减一 选出某些操作,使$ ...

  3. E1. Array and Segments (Easy version)(暴力) && E2. Array and Segments (Hard version)(线段树维护)

    题目链接: E1:http://codeforces.com/contest/1108/problem/E1 E2:http://codeforces.com/contest/1108/problem ...

  4. Codeforces Round #535 (Div. 3) E2. Array and Segments (Hard version) 【区间更新 线段树】

    传送门:http://codeforces.com/contest/1108/problem/E2 E2. Array and Segments (Hard version) time limit p ...

  5. CF1108E2 Array and Segments (Hard version)

    线段树 对于$Easy$ $version$可以枚举极大值和极小值的位置,然后判断即可 但对于$Hard$ $version$明显暴力同时枚举极大值和极小值会超时 那么,考虑只枚举极小值 对于数轴上每 ...

  6. Array and Segments (Easy version) CodeForces - 1108E1 (暴力枚举)

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

  7. 【Codeforces 1108E1】Array and Segments (Easy version)

    [链接] 我是链接,点我呀:) [题意] 题意 [题解] 枚举最大值和最小值在什么地方. 显然,只要包含最小值的区间,都让他减少. 因为就算那个区间包含最大值,也无所谓,因为不会让答案变小. 但是那些 ...

  8. CF E2 - Array and Segments (Hard version) (线段树)

    题意给定一个长度为n的序列,和m个区间.对一个区间的操作是:对整个区间的数-1可以选择任意个区间(可以为0个.每个区间最多被选择一次)进行操作后,要求最大化的序列极差(极差即最大值 - 最小值).ea ...

  9. Codeforces 1108E (Array and Segments) 线段树

    题意:给你一个长度为n的序列和m组区间操作,每组区间操作可以把区间[l, r]中的数字都-1,请选择一些操作(可以都不选),使得序列的最大值和最小值的差值尽量的大. 思路:容易发现如果最大值和最小值都 ...

随机推荐

  1. windows ffmpeg 推送摄像头数据到rtmp服务

    文本主要讲述windows系统下如何利用ffmpeg获取摄像机流并推送到rtmp服务,命令的用法前文 中有讲到过,这次是通过代码来实现.实现该项功能的基本流程如下: 图1 ffmpeg推流流程图 较前 ...

  2. 你必须了解的java内存管理机制(一)-运行时数据区

    前言 本打算花一篇文章来聊聊JVM内存管理机制,结果发现越扯越多,于是分了四遍文章(文章讲解JVM以Hotspot虚拟机为例,jdk版本为1.8),本文为其中第一篇.from 你必须了解的java内存 ...

  3. canvas 橡皮擦效果制作

    擦除一定数量后全部消失的有用 imageData 方法的 我把代码贴在最下面 <!DOCTYPE html> <html> <head> <meta char ...

  4. live555中fDurationInMicroseconds的计算

    live555中fDurationInMicroseconds表示单个视频或者音频帧所占用的时间间隔,也表示在fDurationInMicroseconds微秒时间后再次向Source进行getNex ...

  5. 判断一个IP地址是否是本局域网内地址

    //        /// <summary>        /// 判断一个IP地址是否是本局域网内地址,是返回true 否则返回false,        /// </summa ...

  6. tomcat servlet JSP common gateway interface 公共网关接口

    Tomcat主要充当servlet/JSP容器,不过它却有大量的功能可以与传统的Web服务器相媲美,对公共网关接口(Common Gateway Interface)的支持就是其中之一. 传统的Web ...

  7. Hadoop实战-使用Eclipse开发Hadoop API程序(四)

    一.准备运行所需Jar包 1)avro-1.7.4.jar 2)commons-cli-1.2.jar 3)commons-codec-1.4.jar 4)commons-collections-3. ...

  8. DuiLib笔记之Window常用属性

    caption 可拖拽以移动窗口的标题区,类型:RECT.例如,要指定标题区高度为35,可设置caption="0,0,0,35" mininfo 窗口最小尺寸,类型:SIZE.例 ...

  9. Linux ARM交叉编译工具链制作过程【转】

    本文转载自:http://www.cnblogs.com/Charles-Zhang-Blog/archive/2013/02/21/2920999.html 一.下载源文件 源代码文件及其版本与下载 ...

  10. hdu1015 Safecracker —— 回溯

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1015 代码1: #include<stdio.h>//hdu1015 #include&l ...