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

分析: 我们可以通过枚举最大或者最小值出现的位置 , 然后把不包括最大值位置或者包括最小值位置的区间选取 , 如果数据小我们是可以通过暴力的 , 但是这里的n有1e5 , 那我们就需要借助数据结构了 , 我们很容易可以看出是线段树的区间修改与区间最值 , 但是有个问题 , 我们枚举的过程中选区出来的区间还要进行回复 , 所有这里有个很精妙的东西:

我们可以对操作区间进行整理,使得在枚举过程中,不需要重复进行区间操作。
比如我们现在枚举的最小值位置是p,则我们需要选择包含了p的所有区间。
那么p前面一个状态p-1,进行的区间操作是包含了p-1的所有区间,这些p-1区间中,有些是包含了p的,有些是没包含p的,那么我们需要先删除掉没包含p的区间的影响(即把这些区间减掉的1给加回来)。同时还需要补上包含了p但是不包含p-1的区间(这样选择,就不会和p-1里面保留了的区间重复)。
包含了p-1,但不包含p的区间,显然是以p-1结尾的区间。我们用add[]数组保存以r[i]结尾的区间的编号。
包含了p,但不包含p-1的区间,显然是以p开始的区间。我们用sub[]数组保存以l[i]开始的区间的编号。
区间修改操作,就要用到线段树了。
最后输出答案时,使用最终确定的最小值的位置P,包含P的区间留下,不包含P的舍弃。
---------------------

#include <bits/stdc++.h>

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;//d记录最大极差,p记录最小值的位置
for(int i = ; i <= n; i++)//枚举最小值出现的位置
{
for(int j = ; j < add[i - ].size(); j++)//消除包含i-1,不包含i区间的影响
{
int id = add[i - ][j];//注意这里是i-1
update(, l[id], r[id], );
} for(int j = ; j < sub[i].size(); j++)//添加包含i,不包含i-1区间的影响
{
int id = sub[i][j];
update(, l[id], r[id], -);
} //查询极差 注意这里虽然知道最小值是a[i],但是由于使用了线段树,有lazy标记,标记可能没有更新到最底层,所以不能直接使用a[i]。
int det = query_max(, , n) - query_min(, , n);
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++)
{
if(i != )
printf(" ");
printf("%d", ans[i]);
}
printf("\n");
return ;
}

参考与原文:https://blog.csdn.net/Floraqiu/article/details/86632558

CF E2 - Array and Segments (Hard version) (线段树)的更多相关文章

  1. 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 ...

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

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

  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 1108E2 Array and Segments (Hard version) 差分, 暴力

    Codeforces 1108E2 E2. Array and Segments (Hard version) Description: The only difference between eas ...

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

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

  6. 1304F2 - Animal Observation (hard version) 线段树or单调队列 +DP

    1304F2 - Animal Observation (hard version) 线段树or单调队列 +DP 题意 用摄像机观察动物,有两个摄像机,一个可以放在奇数天,一个可以放在偶数天.摄像机在 ...

  7. CF1108E2 Array and Segments (Hard version)

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

  8. CF 552(div 3) E Two Teams 线段树,模拟链表

    题目链接:http://codeforces.com/contest/1154/problem/E 题意:两个人轮流取最大值与旁边k个数,问最后这所有的数分别被谁给取走了 分析:看这道题一点思路都没有 ...

  9. CF 666E Forensic Examination 【SAM 倍增 线段树合并】

    CF 666E Forensic Examination 题意: 给出一个串\(s\)和\(n\)个串\(t_i\),\(q\)次询问,每次询问串\(s\)的子串\(s[p_l:p_r]\)在串\(t ...

随机推荐

  1. 在Win7 64位电脑上安装Sql Server 2008 R2 Express

    安装环境说明: 操作系统:Win7 64位 英文版 安装步骤: 1.准备安装文件 下载网址:https://www.microsoft.com/zh-CN/download/details.aspx? ...

  2. 19. AUTO INCREMENT 字段

    Auto-increment 会在新记录插入表中时生成一个唯一的数字. AUTO INCREMENT 字段 我们通常希望在每次插入新记录时,自动地创建主键字段的值. 我们可以在表中创建一个 auto- ...

  3. Luogu 3957 [NOIP2017]普及组 跳房子

    写了好久,感觉自己好菜,唉…… 首先发现这个$g$的取值具有单调性,可以想到二分答案,然后考虑用$dp$来检验,这样子可以写出朴素的转移方程: 设$f_i$表示以$i$结尾的最大价值,那么有$f_i ...

  4. Part5核心初始化_lesson4---关闭mmu

    1.ARM存储体系 2.cache 3.虚拟地址 那么谁来完成把虚拟地址转换成物理地址呢? 4.这个工作就由MMU来转换!! 5.关闭MMU和cache 他们都是通过cp15协处理器来控制的!应该在A ...

  5. Office Web APP预览如何去掉顶部版权标志“Microsoft Office Web Apps”

    在Office Web APP的预览会涉及4中类型的文 件:Word.Excel.PowerPoint.PDF,不同的类型在预览时调用的文件是不一样的,其中Word和 PDF调用的是同一个文件.每个预 ...

  6. Densely Connected Convolutional Networks(緊密相連卷積網絡)

    - Dense blocks where each layer is connected to every other layer in feedforward fashion(緊密塊是指每一個層與每 ...

  7. ArcGIS Desktop和Engine中对点要素图层Graduated Symbols渲染的实现 Rotation Symbol (转)

    摘要         ArcGIS中,对于要素图层的渲染,支持按照要素字段的值渲染要素的大小,其中Graduated Symbols可以对大小进行分级渲染.在个人开发系统的过程中,也可以用来美化数据显 ...

  8. 安卓手机传递文件到Windows系统电脑

    1.需求说明 安卓手机传递文件到Windows系统电脑上不太方便,传递文件的原理花样太多.这里介绍纯净原生的蓝牙文件传递方式. 2.操作步骤 2.1 打开侧边栏面板 2.2 打开蓝牙,右键转至设置 2 ...

  9. 跳转iPhone设置页面,绕过审核

    1.问题描述 跳转iPhone设置页面之前都是通过 App-Prefs:root=WIFI 来跳转,但是2018年6月废弃了这个函数,被认为是私有函数,审核会被拒绝. 有心人采用了字符串转码的方式来规 ...

  10. Laravel-安装composer

    一.系统环境   Laravel框架有些系统上的要求,因此需要保证自己运行环境.要求的环境有:对于PHP的版本要求比较法高,其他的是扩展,可以在php.ini文件中开启 PHP >= 5.5.9 ...