首页 > 其他分享 >Luogu P4425 转盘 题解 [ 黑 ] [ 线段树 ] [ 贪心 ] [ 递归 ]

Luogu P4425 转盘 题解 [ 黑 ] [ 线段树 ] [ 贪心 ] [ 递归 ]

时间:2024-08-29 14:50:36浏览次数:11  
标签:递归 int 题解 线段 tr Luogu 最小值 max P4425

转盘:蒟蒻的第一道黑,这题是贪心和线段树递归合并的综合题。

贪心

破环成链的 trick 自然不用多说。

首先观察题目,很容易发现一个性质:只走一圈的方案一定最优。这个很容易证,因为再绕一圈回来标记前面的和等前面的标记完之后继续走是等价的,并且再绕一圈甚至可能更劣。

于是,我们只用走一圈,并且在走路的途中走走停停,就可以走出最优解。

但这依然不怎么好求,通过观察发现:我们把所有停下的时间移到前面来,在起点就把要停的时间全部停掉,和走走停停是等价的,并且这样更好求。

接下来我们就来推式子了:

假设当前的时间是 \(t\),我们从 \(i\) 出发,要走到 \(j\) 处,并且 \(j\) 处的最早出现时间为 \(a_j\),那么可以列出方程:

\[t+(j-i)\ge a_j \]

移项得:

\[t \ge a_j-j+i \]

因此在此时 \(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;
}

标签:递归,int,题解,线段,tr,Luogu,最小值,max,P4425
From: https://www.cnblogs.com/zhr0102/p/18386640

相关文章

  • 题解:P9938 [USACO21OPEN] Acowdemia II B
    前言:原来的tj干了一堆什么建图啊之类的,但其实不要这么复杂。注:下文中\(n\)是各成员名字列表。从\(K=1\)开整。如果情况是\(n_i<n_{i+1}<\cdots<n_j\),那么显然,咱就不知道关于成员\(n_i,\cdots,n_j\)的相对资历的信息。也许所有这帮成员都做出了相同的贡献。......
  • AWTF2024A Moving Slimes 题解
    发现史莱姆不合并也不会影响答案,所以就不用考虑合并了。这样处理之后,史莱姆的移动可以看作是受到与其不在同一位置的史莱姆的吸引所完成的,每只史莱姆可以给其他史莱姆一个单位的吸引力。因为每只史莱姆提供的吸引力是恒定的,所以考虑把吸引力放在它们的重心上,设\(pre_i\)表示坐......
  • 历年CSP-J初赛真题解析 | 2016年CSP-J初赛阅读程序(23-26)
    学习C++从娃娃抓起!记录下CSP-J备考学习过程中的题目,记录每一个瞬间。附上汇总贴:历年CSP-J初赛真题解析|汇总_热爱编程的通信人的博客-CSDN博客#include<iostream>usingnamespacestd;intmain(){intmax,min,sum,count=0;inttmp;cin>>tmp;......
  • CF1286E Fedya the Potter Strikes Back 题解
    题目链接点击打开链接题目解法牛题!题目实际上是要每次加入一个字符,求所有的\(border\)的神秘度之和考虑从前\(i-1\)个字符到前\(i\)个字符\(border\)的变化如果\(str_1=str_i\),会加入长度为\(1\)的\(border\),这一部分可以暴力加且只会保留\(i-1\)的\(border......
  • 华为java岗经典面试题解析
    题目为在一个整形的数组中,在数组中只有一值个是不重复的,其他的值都是有两个重复的值,找出不重复的那个值。{11,11,12,13,13,16,16}解析为当用Java来解决这个问题时,可以使用异或运算来找出只出现一次的元素。以下是一个示例Java程序,演示了如何在一个整型数组中找出只出现一次的元......
  • 洛谷P5322 [BJOI2019] 排兵布阵 题解
    代码#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongintdp[20001],a[101][101],s,n,m;signedmain(){ cin>>s>>n>>m; for(intj=1;j<=s;j++){ for(inti=1;i<=n;i++){ cin>>a[i][j]; } } for(inti=1;......
  • 局域网内两台设备只有一方可以ping通问题解决
    场景局域网内有两台笔记本,都是windows系统,都是连接的同一个路由器,在同一个网段中。但是其中的一台笔记本192.168.1.101,另外一台是192.168.1.100ping命令测试发现192.168.1.101无法ping通192.168.1.100这是为什么呢?排查与修复首先的两台电脑为了安全,防火墙都是开启的。既然......
  • Atcoder [AGC006D] Median Pyramid Hard 题解 [ 紫 ] [ 二分 ] [ adhoc ]
    MedianPyramidHard:二分trick加上性质观察题。trick我们可以二分值域,然后把大于等于它的数标记成\(1\),其他标记为\(0\)(有些题需要标记成\(-1\)),然后根据这个来check方案是否可行,这通常通过判断某个数是否是\(1\)来实现。本质上其实就是check大于等于它的数能否成为......
  • 文件排版 题解
    前言题目链接:HDU。题意简述给\(n\)个单词和一张图片排版。每个单词长度为\(a_i\)。图片占行不确定,但是占列始终为\([dw+1,dw+pw]\)。排版宽度为\(W\),高度无限制。要求单词间有长度为\(1\)的空格,单词不能超出宽度\(W\),不能覆盖在图片上,单词间相对顺序不能发生改变......
  • 题解 [ABC199F] Graph Smoothing(中文/English)
    本题解提供英文版,位于示例代码之后。Englishversionofthiseditorialisprovidedafterthesamplecode.设行向量:\[A^{(k)}=\begin{bmatrix}a_1^{(k)}&a_2^{(k)}&\cdots&a_n^{(k)}\end{bmatrix}\]表示\(k\)次操作后每个节点点权的期望。特别地,\(A^{(0)}\)表......