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. HTML5、CSS3等新特性:

    HTML5:1/绘画 canvas 元素;2/用于媒介回放的 video 和 audio 元素;3/本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失;4/sessionSt ...

  2. AsyncTask源代码解析

    快要毕业了.近期在阿里巴巴校园招聘面试,一面过了,感觉挺轻松,可能是运气好.面试官感觉比我腼腆一些.我俩从android绕到了spring mvc 到数据库悲观锁 到linux 然后又会到了andro ...

  3. Android gdb so

    gdb debug an android application 1.gdb 要有gdbserver 一般模拟器默认装有gdbserver,如2.3.3的模拟器,看一下有没有: D:\Develope ...

  4. SharePoint ULS Log Viewer 日志查看器

    SharePoint ULS Log Viewer 日志查看器 项目描写叙述 这是一个Windows应用程序,更加轻松方便查看SharePoint ULS日志文件.支持筛选和简单的视图. 信息 这是一 ...

  5. Jenkins 搭建

    持续集成(CI continuous integration) 可以做什么? 自动构建.定时触发,或由某个事件触发.比如可以做 daily build,或每次代码提交时触发.这样可以最早发现代码编译和 ...

  6. MySQL 导入导出命令(转载)

    导出数据: mysqldump --databases -u root -p密码 数据库名> /root/guogl/XXX.sql 从sql文件导入数据: mysql -u root -p密码 ...

  7. MongoDB 操作手冊CRUD 事务 两步提交

    运行两步提交 概述 这部分提供了多记录更新或者多记录事务.使用两步提交来完毕多记录写入的模板. 另外.能够扩展此方法来提供rollback-like功能. 背景 MongoDB对于单条记录的操作是原子 ...

  8. android lanchmode

    http://www.cnblogs.com/xiaoQLu/archive/2012/07/17/2595294.html http://www.cnblogs.com/lwbqqyumidi/p/ ...

  9. 【BZOJ3197】[Sdoi2013]assassin 树同构+动态规划+KM

    [BZOJ3197][Sdoi2013]assassin Description Input Output Sample Input 4 1 2 2 3 3 4 0 0 1 1 1 0 0 0 Sam ...

  10. memcmp和strcmp的返回值

    注意,无论是内存比较还是字符串比较,这两个函数的返回值的意义是一样的. 如果相同,返回0 如果前面大于后面,返回大于0 如果前面小于后面,返回小于0 一定要注意,相同的时候是0,不是true.