Codeforces 484 E. Sign on Fence
[传送门]
题意就是给一排围栏,每个围栏都有一个高度,查询区间$\left[l, r\right]$之间长度为$w$的子区间的最小高度的最大值。
首先,这个最大值肯定是这个区间里的围栏的某个高度,如果是一个未出现过的高度,显然能有更高的高度满足条件。
那么就可以考虑在离散化后的高度数组里二分答案,然后check一下这个区间里是否有连续$w$个围栏的高度大于等于这个答案。
因为答案肯定是出现过的高度这个性质,那么可以考虑以高度建一棵可持久化线段树,先将高度数组离散化排好序,第$i$个版本的线段树代表的是下标位置的围栏的高度是否大于等于$h_i$,然后保存区间前缀最长连续1、后缀最长连续1、区间最长连续1。第$i$个版本由第$i-1$个版本再加上几个单点修改得来。
查询就保存区间最长前缀及最长后缀进行合并,合并过程更新一下答案。
说起来容易想起来难。我菜爆了。
#include <bits/stdc++.h>
using namespace std; const int N = 1e5 + ;
int n, a[N], h[N], root[N], tol, ans;
vector<int> G[N]; struct Seg {
struct Tree {
int lp, rp, len, pre, suf, mx;
} tree[N * ];
inline void pushup(int p) {
tree[p].pre = tree[tree[p].lp].pre + (tree[tree[p].lp].pre == tree[tree[p].lp].len ? tree[tree[p].rp].pre : );
tree[p].suf = tree[tree[p].rp].suf + (tree[tree[p].rp].suf == tree[tree[p].rp].len ? tree[tree[p].lp].suf : );
tree[p].mx = max(tree[tree[p].lp].suf + tree[tree[p].rp].pre, max(tree[tree[p].lp].mx, tree[tree[p].rp].mx));
}
void build(int &p, int l, int r) {
p = ++tol;
tree[p].len = tree[p].pre = tree[p].suf = tree[p].mx = r - l + ;
if (l == r) return;
int mid = l + r >> ;
build(tree[p].lp, l, mid);
build(tree[p].rp, mid + , r);
}
void update(int &p, int q, int l, int r, int pos) {
tree[p = ++tol] = tree[q];
if (l == r) {
tree[p].pre = tree[p].suf = tree[p].mx = ;
return;
}
int mid = l + r >> ;
if (pos <= mid) update(tree[p].lp, tree[q].lp, l, mid, pos);
else update(tree[p].rp, tree[q].rp, mid + , r, pos);
pushup(p);
}
pair<int, int> query(int p, int l, int r, int x, int y) {
if (x <= l && y >= r) {
ans = max(ans, tree[p].mx);
return pair<int, int>(tree[p].pre, tree[p].suf);
}
int mid = l + r >> ;
pair<int, int> L(, ), R(, );
if (x <= mid) L = query(tree[p].lp, l, mid, x, y);
if (y > mid) R = query(tree[p].rp, mid + , r, x, y);
ans = max(ans, L.second + R.first);
return pair<int, int>(L.first + (L.first == tree[tree[p].lp].len ? R.first : ),
R.second + (R.second == tree[tree[p].rp].len ? L.second : ));
}
} seg; int main() {
scanf("%d", &n);
for (int i = ; i <= n; i++)
scanf("%d", &a[i]), h[i] = a[i];
sort(h + , h + + n);
int cnt = unique(h + , h + + n) - h - ;
for (int i = ; i <= n; i++) {
int pos = lower_bound(h + , h + + cnt, a[i]) - h;
G[pos].push_back(i);
}
seg.build(root[], , n);
for (int i = ; i <= cnt; i++) {
root[i] = root[i - ];
for (int x: G[i - ]) {
seg.update(root[i], root[i], , n, x);
}
}
int q;
scanf("%d", &q);
while (q--) {
int x, y, w;
scanf("%d%d%d", &x, &y, &w);
int res = ;
int l = , r = cnt;
while (l <= r) {
int mid = (l + r + ) >> ;
ans = ;
seg.query(root[mid], , n, x, y);
if (ans >= w) l = mid + , res = mid;
else r = mid - ;
}
printf("%d\n", h[res]);
}
return ;
}
Codeforces 484 E. Sign on Fence的更多相关文章
- CF&&CC百套计划4 Codeforces Round #276 (Div. 1) E. Sign on Fence
http://codeforces.com/contest/484/problem/E 题意: 给出n个数,查询最大的在区间[l,r]内,长为w的子区间的最小值 第i棵线段树表示>=i的数 维护 ...
- Codeforces 484E Sign on Fence(是持久的段树+二分法)
题目链接:Codeforces 484E Sign on Fence 题目大意:给定给一个序列,每一个位置有一个值,表示高度,如今有若干查询,每次查询l,r,w,表示在区间l,r中, 连续最长长度大于 ...
- Codeforces Round #276 (Div. 1) E. Sign on Fence 二分+主席树
E. Sign on Fence Bizon the Champion has recently finished painting his wood fence. The fence consi ...
- AC日记——Sign on Fence Codeforces 484e
E. Sign on Fence time limit per test 4 seconds memory limit per test 256 megabytes input standard in ...
- CF 484E - Sign on Fence
E. Sign on Fence time limit per test 4 seconds memory limit per test 256 megabytes input standard in ...
- 【CF484E】Sign on Fence(主席树)
[CF484E]Sign on Fence(主席树) 题面 懒得贴CF了,你们自己都找得到 洛谷 题解 这不就是[TJOI&HEOI 排序]那题的套路吗... 二分一个答案,把大于答案的都变成 ...
- CF484E Sign on Fence && [国家集训队]middle
CF484E Sign on Fence #include<bits/stdc++.h> #define RG register #define IL inline #define _ 1 ...
- Codeforces Round #276 (Div. 1) E. Sign on Fence (二分答案 主席树 区间合并)
链接:http://codeforces.com/contest/484/problem/E 题意: 给你n个数的,每个数代表高度: 再给出m个询问,每次询问[l,r]区间内连续w个数的最大的最小值: ...
- Sign on Fence CodeForces - 484E
http://codeforces.com/problemset/problem/484/E 题意: 给定一个长度为n的数列,有m次询问,询问形如l r k 要你在区间[l,r]内选一个长度为k的区间 ...
随机推荐
- 词向量实践(gensim)
词向量训练步骤: 分词并去停用词 词频过滤 训练 项目完整地址:https://github.com/cyandn/practice/tree/master/Word2Vec gensim中Word2 ...
- [转帖]spring boot项目集成jacoco
小试牛刀:spring boot项目集成jacoco 2019-03-28 20:14:36 zyq23333 阅读数 509 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议, ...
- [转帖]OLAP引擎这么多,为什么苏宁选择用Druid?
OLAP引擎这么多,为什么苏宁选择用Druid? 原创 51CTO 2018-12-21 11:24:12 [51CTO.com原创稿件]随着公司业务增长迅速,数据量越来越大,数据的种类也越来越丰富, ...
- B树索引最通俗易懂的介绍
先来一段有莫的对话: 前几天下班回到家后正在处理一个白天没解决的bug,厕所突然传来对象的声音: 对象:xx,你有<时间简史>吗? 我:我去!妹子,你这啥癖好啊,我有时间也不会去捡屎 ...
- .Net调用ffmpeg对视频截图
2019/10/27, .Net c#代码片段 摘要:借助ffmpeg对视频/图片截图.生成缩略图,使用命令行调用ffmpeg工具,支持Linux和Windows 网上很多版本都是需要等待4s的做法, ...
- JVM故障分析系列之四:jstack生成的Thread Dump日志线程状态
JVM故障分析系列之四:jstack生成的Thread Dump日志线程状态 2017年10月25日 Jet Ma JavaPlatform JVM故障分析系列系列文章 JVM故障分析系列之一: ...
- 使用基础知识完成java小作业?强化练习-1.输入数组计算最大值-2.输出数组反向打印-3.求数组平均值与总和-4.键盘输两int,并求总和-5.键盘输三个int,并求最值;
完成几个小代码练习?让自己更加强大?学习新知识回顾一下基础? 1.输入数组计算最大值 2.输出数组反向打印 3.求数组平均值与总和 4.键盘输两int,并求总和 5.键盘输三个int,并求最值 /* ...
- python基础流程控制
流程控制主要分为三大类: 1.if 判断语句 2.while 循坏语句 3.for 循坏语句 下面以举例说明: if 判断语句: user1 = 'seven' user2 = 'alex' pass ...
- DOS常见命名整理
Dos命令 1.打开终端的方式 (1).window+R / 点击开始栏,输入cmd,然后回车 (2).在某个文件夹下打开终端 按住shift+右击,有个在此处打开命令窗口 2.修改终端背景和文字颜色 ...
- golang中uint8字节切片转字符串
假如拿到了一个字节切片test1 = {'a', 'b', 'c', 'd', 11} package main import ( "fmt" "reflect" ...