BZOJ5286: [Hnoi2018]转盘 (线段树)
题意
给你绕成一圈的物品共 \(n\) 个 , 然后从其中一个开始选 , 每次有两种操作 ,
一是继续选择当前物品 , 二是选择这个后一个物品 .
选择后一个物品要求当前的时刻大于后一个的 \(T_i\) . 第一次选择的时候也要满足这个条件 .
求选完所有物品的最小时间 .
并且有 \(m\) 次修改 , 每次修改一个点的 \(T_i\) , 修改后询问当前的答案 .
部分点要求强制在线 .
\((n \le 100000 , m \le 100000 , T_i \le 100000)\)
题解
首先化环为链 .
然后我们枚举一个起点 , 然后考虑它的答案是什么 .
假设起点后面有点 \(i\) 那么令 \(L_i\) 为 \(T_i\) 与从 \(i+1\) 到当前终点的长度和 .
不难发现 其实就是这个序列中的 \(L_i\) 的最大值就是当前枚举起点的答案 .
这是因为 , 我们考虑从一个点后继续走 , 那么如果当前是最大的 , 就一下可以走到底 .
不是的话也没关系 , 因为我们就是当前起点求最大值耗费就行了.
然后我们要求最小的时间 .
写出式子就有
\]
令 \(P_i = T_i - i\) .
我们简单整理就得到
\]
此处后面 \(\max\) 维护的终点可以到 \(2n\) . 为什么呢? 因为后面的会循环前面的 \(T_i\) 但 \(i\) 变大 , 所以不会影响 \(\max\) 的答案.
如何考虑动态维护这个式子呢 ?
不难发现这个和 楼房重建 很像... 可考试的时候我并没有做过 , 只听过 ,
那么就愉快的只维护了后面 \(\max\) 2333
我们考虑用线段树维护两个东西 假设当前区间为 \([l,r]\) 中点为 \(mid\).
- \(\displaystyle \min_{i=l}^{mid} \{i + \max_{j = i} ^{r} P_j\}\) .
- \(\displaystyle \max_{i=l}^r P_i\) .
第二个很好维护 , 主要是第一个如何维护 并且 为什么要维护 .
我们对于任意一个区间 考虑维护这个东西 , 需要将左边很多区间进行考虑 , 是否能优化当前答案 .
假设 \(\displaystyle \max_{i=mid + 1}^{r} P_i = v\) .
那么我们考虑另外一个区间 \([l', r']\) 此处 \(r' \le mid\) .
如果 \(\displaystyle v \ge \max_{i=mid'+1} ^{r'} P_i\) 那么显然当前的最优答案在 \([l',mid']\)
为什么呢 因为他们的 \(\max\) 一样 那么下标越小越优 .
如果 \(\displaystyle v < \max_{i=mid'+1} ^{r'} P_i\) 那么当前的答案在左右两个区间都是可能的 ,
但左区间的答案我们之前已经计算过了并且 \(\max\) 不会进行改变 所以可以直接用
右区间的我们继续递归下去计算就行了
有一个细节 就是到底了后 \(l'+1+v\) \((l' != mid)\) 也可以是最优解
因为当前递归到最底层时的 \(\max\) 可能很大 不够优秀..
为什么要维护这个呢 , 因为通过小的区间 , 我们可以逐渐维护出更大的区间的答案 , 并且不会漏掉情况 .
然后时间复杂度就是 \(O(n \log ^ 2 n)\) .
\([n+1,2n]\) 的这个 \(\min\) 没必要维护 常数可以除以 \(2\) ... (目前 \(BZOJ \ rk2\) )
代码
/**************************************************************
Problem: 5286
User: zjp_shadow
Language: C++
Result: Accepted
Time:3472 ms
Memory:17080 kb
****************************************************************/
#include<bits/stdc++.h>
#define For(i, l, r) for(int i = (l), i##end = (int)(r); i <= i##end; ++ i)
#define Fordown(i, r, l) for (int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std;
inline bool chkmin(int &a, int b) { return b < a ? a = b, 1 : 0; }
inline bool chkmax(int &a, int b) { return b > a ? a = b, 1 : 0; }
inline int read() {
int x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * fh;
}
int n, m, p;
const int N = 1e5 + 1e3, inf = 0x3f3f3f3f;
#define lson o << 1, l, mid
#define rson o << 1 | 1, mid + 1, r
struct Segment_Tree {
int maxv[N * 20], minv[N * 20];
int Query(int o, int l, int r, int qr, int qv) {
if (l == r) return min(l + max(maxv[o], qv), l == qr ? inf : l + 1 + qv);
int mid = (l + r) >> 1;
if (qv >= maxv[o << 1 | 1]) return Query(lson, qr, qv);
return min(minv[o], Query(rson, qr, qv));
}
void Update(int o, int l, int r, int up, int uv) {
if (l == r) { maxv[o] = uv; return; }
int mid = (l + r) >> 1;
if (up <= mid) Update(lson, up, uv); else Update(rson, up, uv);
maxv[o] = max(maxv[o << 1], maxv[o << 1 | 1]);
if (l <= n) minv[o] = Query(lson, mid, maxv[o << 1 | 1]);
}
} T;
int ans;
int main() {
n = read(); m = read(); p = read();
For (i, 1, n) {
int val = read();
T.Update(1, 1, n * 2, i, val - i);
T.Update(1, 1, n * 2, i + n, val - (i + n));
}
int x = 0, y = 0;
For (i, 0, m) {
if (i) x = read() ^ (p * ans), y = read() ^ (p * ans);
if (x) T.Update(1, 1, n * 2, x, y - x), T.Update(1, 1, n * 2, x + n, y - (x + n));
ans = T.minv[1] + n - 1;
printf ("%d\n", ans);
}
return 0;
}
BZOJ5286: [Hnoi2018]转盘 (线段树)的更多相关文章
- BZOJ.5286.[AHOI/HNOI2018]转盘(线段树)
BZOJ LOJ 洛谷 如果从\(1\)开始,把每个时间\(t_i\)减去\(i\),答案取决于\(\max\{t_i-i\}\).记取得最大值的位置是\(p\),答案是\(t_p+1+n-1-p=\ ...
- [HNOI/AHOI2018]转盘(线段树优化单调)
gugu bz lei了lei了,事独流体毒瘤题 一句话题意:任选一个点开始,每个时刻向前走一步或者站着不动 问实现每一个点都在$T_i$之后被访问到的最短时间 Step 1 该题可证: 最优方案必 ...
- 洛谷P4425 [HNOI/AHOI2018]转盘(线段树)
题意 题目链接 Sol 首先猜一个结论:对于每次询问,枚举一个起点然后不断等到某个点出现时才走到下一个点一定是最优的. 证明不会,考场上拍了3w组没错应该就是对的吧... 首先把数组倍长一下方便枚举起 ...
- bzoj5286 [Hnoi2018]转盘
题目描述: bz luogu 题解: 看了半个晚上终于明白了. 首先最优决策一定有:在起始点停留一段时间然后一直前进. 解释网上有很多,在这里不赘述了. (由于是环,先把$T$数组倍长.) 首先基于决 ...
- 【BZOJ5286】[HNOI2018]转盘(线段树)
[BZOJ5286][HNOI2018]转盘(线段树) 题面 BZOJ 洛谷 题解 很妙的一道题目啊.(全世界除了我这题都有40分,就我是一个状压选手 首先来发现一些性质,我们走一圈一定不会更差. 为 ...
- [BZOJ5286][洛谷P4425][HNOI2018]转盘(线段树)
5286: [Hnoi2018]转盘 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 15 Solved: 11[Submit][Status][Di ...
- BZOJ5286 HNOI/AHOI2018转盘(分块/线段树)
显然最优走法是先一直停在初始位置然后一次性走完一圈.将序列倍长后,相当于找一个长度为n的区间[l,l+n),使其中ti+l+n-1-i的最大值最小.容易发现ti-i>ti+n-(i+n),所以也 ...
- [HNOI2018]转盘[结论+线段树]
题意 题目链接 分析 首先要发现一个结论:最优决策一定存在一种 先在出发点停留之后走一圈 的情况,可以考虑如下证明: 如果要停留的话一定在出发点停留,这样后面的位置更容易取到. 走超过两圈的情况都可以 ...
- 洛谷P4425 转盘 [HNOI/AHOI2018] 线段树+单调栈
正解:线段树+单调栈 解题报告: 传送门! 1551又是一道灵巧连题意都麻油看懂的题,,,,所以先解释一下题意好了,,,, 给定一个n元环 可以从0时刻开始从任一位置出发 每次可以选择向前走一步或者在 ...
随机推荐
- BZOJ 2784 时间流逝
BZOJ 2784 时间流逝 古典概率论... 可以发现由于能量圈数量限制,所以所构成的必定为树状结构(即便是转成最小能量圈和能量圈权值和之后存在重复状态,但是每个状态的含义不同,而且不能自身转移自身 ...
- HDU 1109 Run Away
题目大意:给一个矩阵的长宽,再给n个点,求矩阵区域内某个点到各个点的最小距离的最大值,输出所求点的坐标 这道题我还是写了随机化乱搞,不过由于比较懒于是就没有写模拟退火,不过也是可以AC的 我们先初始随 ...
- [开源 .NET 跨平台 Crawler 数据采集 爬虫框架: DotnetSpider] [四] JSON数据解析
[DotnetSpider 系列目录] 一.初衷与架构设计 二.基本使用 三.配置式爬虫 四.JSON数据解析与配置系统 五.如何做全站采集 场景模拟 接上一篇, JD SKU对应的店铺信息是异步加载 ...
- Reactjs-JQuery-Omi-Extjs-Angularjs对比
写在前面 前端越来越混乱了,当然也可以美其名曰:繁荣. 当新启动一个前端项目,第一件事就是纠结:使用什么框架,重造什么轮子? 那么,希望看完此篇,能够给你一个清晰的认识,或者让你更加地纠结和无所适从 ...
- 【nodejs】让nodejs像后端mvc框架(asp.net mvc)一样处理请求--目录(8/8 完结)
为什么要做这个 在使用nodejs开发过程中,总是发现需要做很多重复性的体力劳动,且因为自身是服务端程序员出身,感觉有一些服务端好的东西其实可以在nodejs上得到应用并能提高一些开发工作效率. 本系 ...
- easyUI中textbox或number的数值大小校验
例:textbox里面,要求做两个textbox名字为(A,B),其中两个的数字大小范围是-10~10之间,之后其中A的值必须大于B所填的数字,如果输入错误,则提示出弹出框,并清空数据. <!D ...
- C++高质量编程笔记
/* * 函数介绍: * 输入参数: * 输出参数: * 返回值 : */ void Function(float x, float y, float z) { - } if (-) { - whil ...
- 去掉UITabBar和NavigationBar上的黑线
在UITabBarViewController界面设置 self.tabBar.barStyle = UIBarStyleBlack; 在NavigationController界面设置 self.n ...
- MyBatis 返回类型resultType为map时的null值不返回问题
问题一: 查询结果集中 某字段 的值为null,在map中不包含该字段的key-value对 解决:在mybatis.xml中添加setting参数 <!-- 在null时也调用 sett ...
- WIN10 评估版 查看过期时间
命令行运行winver,弹出的窗口显示过期时间,如 下图: 又可以再用一段时间教育版了,本机预装的的家庭版序列号,还没法从教育版降级到家庭版,可悲吧(win7时代就不允许从高级降低到低级用啊)