Luogu P4425 转盘 题解 [ 黑 ] [ 线段树 ] [ 贪心 ] [ 递归 ]
转盘:蒟蒻的第一道黑,这题是贪心和线段树递归合并的综合题。
贪心
破环成链的 trick 自然不用多说。
首先观察题目,很容易发现一个性质:只走一圈的方案一定最优。这个很容易证,因为再绕一圈回来标记前面的和等前面的标记完之后继续走是等价的,并且再绕一圈甚至可能更劣。
于是,我们只用走一圈,并且在走路的途中走走停停,就可以走出最优解。
但这依然不怎么好求,通过观察发现:我们把所有停下的时间移到前面来,在起点就把要停的时间全部停掉,和走走停停是等价的,并且这样更好求。
接下来我们就来推式子了:
假设当前的时间是 \(t\),我们从 \(i\) 出发,要走到 \(j\) 处,并且 \(j\) 处的最早出现时间为 \(a_j\),那么可以列出方程:
\]
移项得:
\]
因此在此时 \(t\) 的最小值就是 \(\max_{j=i}^{i+n-1}(a_j-j+i)\)。
由于每次走路还要计算时间,所以总时间为 \(\max_{j=i}^{i+n-1}(a_j-j+i)+n-1\)。
因为要最小化,所以答案就是 \(\min_{i=1}^{n}(\max_{j=i}^{i+n-1}(a_j-j+i))+n-1\)。
线段树与递归
根据上面的分析,我们需要维护 \(\min_{i=1}^{n}(\max_{j=i}^{i+n-1}(a_j-j+i))+n-1\) 这个式子。
首先 \(\max_{j=i}^{i+n-1}(a_j-j+i)\) 是很好维护的,我们可以通过一个线段树来维护。
但是外面的那个 \(\min_{i=1}^{n}\) 怎么维护?实际上我们可以通过在线段树上递归来实现。
设 \(x\) 表示线段树上某个节点的最小值。因为我们只需要求出起点在 \(1\) 到 \(n\) 中的最小值(后面一部分是复制两倍后的,所以和前面的重复了,可以不要计算),所以 \(x\) 就是这个节点左半部分的最小值,而不是整个节点的最小值。但也不是说按整个节点算就不可以了,只是说这样做代码好写、思路好想一些。
接下来考虑如何递归合并信息:

注意:当前我们处在的节点是 \(l\)。
当递归到叶子节点时
由式子可知,直接返回 \(i+\max(lson_{max},r_{max})\) 即可。
当 \(rson_{max}< r_{max}\) 时
\(r_{max}\) 依然是最大值,所以要接下来递归 \(l\) 的左儿子 \(lson\),因为右儿子已经确定贡献了,贡献就是 \(\min(dfs(lson,r_{max}),mid+1+r_{max})\)。
当 \(rson_{max}\ge r_{max}\) 时
\(rson_{max}\) 把 \(r_{max}\) 挤下去了,所以要接下来递归 \(l\) 的右儿子 \(rson\),以找到右儿子的那个最大值在哪,才能确定贡献,左儿子的贡献就是 \(\min(x_l,dfs(rson,r_{max}))\)。
注意 \(x_l\) 与 \(dfs(p,r_{max})\) 函数的定义不同,其一是表示左半部分的最小值,另一个是表示全部区间的最小值。
其余部分就是按照线段树常规的配置来写了。
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
typedef long long ll;
typedef pair<int,int> pi;
const int N=200005;
int n,m,q,a[N],lastans=0;
struct node{
int l,r;
int mx,mi;
}tr[4*N];
int dfs(int p,int mxr)
{
if(tr[p].l==tr[p].r)return (tr[p].l+max(mxr,tr[p].mx));
int mid=(tr[p].l+tr[p].r)>>1;
if(tr[rc].mx<mxr)return min(dfs(lc,mxr),mid+1+mxr);
return min(tr[p].mi,dfs(rc,mxr));
}
void pushup(int p)
{
tr[p].mx=max(tr[lc].mx,tr[rc].mx);
tr[p].mi=dfs(lc,tr[rc].mx);
}
void build(int p,int ln,int rn)
{
tr[p]={ln,rn,a[ln]-ln,ln+a[ln]-ln};
if(ln==rn)return;
int mid=(ln+rn)>>1;
build(lc,ln,mid);
build(rc,mid+1,rn);
pushup(p);
}
void update(int p,int x,int v)
{
if(tr[p].l==x&&tr[p].r==x)
{
tr[p].mx=v-x;
tr[p].mi=x+v-x;
return;
}
int mid=(tr[p].l+tr[p].r)>>1;
if(x<=mid)update(lc,x,v);
else update(rc,x,v);
pushup(p);
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>q;
for(int i=1;i<=n;i++)cin>>a[i],a[i+n]=a[i];
build(1,1,2*n);
cout<<tr[1].mi+n-1<<endl;
lastans=tr[1].mi+n-1;
while(m--)
{
int x,y;
cin>>x>>y;
if(q)x^=lastans,y^=lastans;
update(1,x,y);
update(1,x+n,y);
cout<<tr[1].mi+n-1<<endl;
lastans=tr[1].mi+n-1;
}
return 0;
}
Luogu P4425 转盘 题解 [ 黑 ] [ 线段树 ] [ 贪心 ] [ 递归 ]的更多相关文章
- [火星补锅] 水题大战Vol.2 T1 && luogu P1904 天际线 题解 (线段树)
前言: 当时考场上并没有想出来...后来也是看了题解才明白 解析: 大家(除了我)都知道,奇点和偶点会成对出现,而出现的前提就是建筑的高度突然发生变化.(这个性质挺重要的,我之前没看出来) 所以就可以 ...
- 洛谷P4425 转盘 [HNOI/AHOI2018] 线段树+单调栈
正解:线段树+单调栈 解题报告: 传送门! 1551又是一道灵巧连题意都麻油看懂的题,,,,所以先解释一下题意好了,,,, 给定一个n元环 可以从0时刻开始从任一位置出发 每次可以选择向前走一步或者在 ...
- Bzoj5251 线段树+贪心
Bzoj5251 线段树+贪心 记录本蒟蒻省选后的第一篇题解!国际惯例的题面:首先这个东西显然是一棵树.如果我们把数值排序,并建立这棵树的dfs序,显然dfs序上的一个区间对应数值的一个区间,且根为数 ...
- BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心
BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心 Description 在计算机中,CPU只能和高速缓存Cache直接交换数据.当所需的内存单元不在Cache中时,则需要从主存里把数 ...
- 2018.10.20 NOIP模拟 蛋糕(线段树+贪心/lis)
传送门 听说是最长反链衍生出的对偶定理就能秒了. 本蒟蒻直接用线段树模拟维护的. 对于第一维排序. 维护第二维的偏序关系可以借助线段树/树状数组维护逆序对的思想建立权值线段树贪心求解. 代码
- luogu P2574 XOR的艺术 (线段树)
luogu P2574 XOR的艺术 (线段树) 算是比较简单的线段树. 当区间修改时.\(1 xor 1 = 0,0 xor 1 = 1\)所以就是区间元素个数减去以前的\(1\)的个数就是现在\( ...
- 【原创】洛谷 LUOGU P3373 【模板】线段树2
P3373 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第 ...
- 【原创】洛谷 LUOGU P3372 【模板】线段树1
P3372 [模板]线段树 1 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别 ...
- 【Luogu】P1607庙会班车Fair Shuttle(线段树+贪心)
我不会做贪心题啊……贪心题啊……题啊……啊…… 我真TM菜爆了啊…… 这题就像凌乱的yyy一样,把终点排序,终点相同的按起点排序.然后维护一个查询最大值的线段树.对于一个区间[l,r],如果这个区间已 ...
- codeforces 675E Trains and Statistic 线段树+贪心统计
分析:这个题刚看起来无从下手 但是我们可以先简化问题,首先可以固定起点i,求出i+1到n的最小距离 它可以到达的范围是[i+1,a[i]],贪心的想,我们希望换一次车可以到达的距离尽量远 即:找一个k ...
随机推荐
- 接口压力测试工具之go-wrk
go-wrk 是一个用Go语言实现的轻量级的http基准测试工具,类似于wrk,本文将简单介绍一下如何使用go-wrk实现接口的性能(压力)测试. github地址:https://github.co ...
- CAD快速图层孤立、隐藏、锁定下载
AutoCAD快速图层孤立.隐藏.锁定插件下载 链接 AutoCAD Quick Layer Isolation, Hide, Lock Plugin Download Link MAG.fas&am ...
- 如何正确使用 RMQ
序列分块.设块长为 \(B\).每块预处理出最大值.对于询问 \([l, r]\),答案就是整块最大值和散块最大值拼起来.答案显然是 \(O(n) \sim O(\dfrac{n}{B} + B)\) ...
- .NET Core 基于 IHostedService 实现后台定时任务
.NET Core 基于 IHostedService 实现后台定时任务 迷恋自留地 NET Core 2.0 引入了 IHostedService ,基于它可以很方便地执行后台任务,.NET Cor ...
- 关于IMultiValueConverter的使用
在前端向后端传递数据的过程中,因为涉及多个属性的调用,将数据绑定到CommandParameter,采用了多值转换器进行数据传递. class MultiBindingConverter : IMul ...
- Qt/C++入门基础学习001-绘图基础
这一节介绍 Qt 的绘图基础知识,我们都知道,Qt 里绘图使用的是 QPainter,但是首先需要弄明白:在什么上绘图和在哪里绘图,然后才是怎么绘图,我们就围绕这几个问题来展开. 在什么上绘图 The ...
- Qt/C++音视频开发53-本地摄像头推流/桌面推流/文件推流/监控推流等
一.前言 编写这个推流程序,最开始设计的时候是用视频文件推流,后面陆续增加了监控摄像头推流(其实就是rtsp视频流).网络电台和视频推流(一般是rtmp或者http开头m3u8结尾的视频流).本地摄像 ...
- Qt编写地图综合应用53-省市轮廓图下载
一.前言 Qt的浏览器控件的交互机制非常方便,所以在在线地图的时候可以对每个区域的经纬度坐标集合发给Qt程序,让他去存储到文件,在实际的测试过程中,发现有部分地图有多个封闭的曲线的,比如散落的岛屿和飞 ...
- 将maven项目打包上传到私服
1. 配置私服账户密码 在maven 的setting.xml 中配置用户名和密码: <servers> <server> <username>deployment ...
- Soulmate
理想之所以是理想,也就是因为它只能存在于脑海中,天上月是天上月,水中花是水中花.但我们仍可以怀揣着对乌托邦的向往,所以,我对理想中的对象设想如下: 原来形容一个女子的眉眼,我总喜欢说眉眼如黛,眉如远山 ...