正题

题目链接:https://www.luogu.com.cn/problem/P7599


题目大意

\(n\)棵树,在某棵树上时可以选择向左右两边第一棵比它高的树跳,现在\(q\)次询问从\([A,B]\)中某个点出发跳到\([C,D]\)中某个点的最少次数。

\(1\leq n\leq 2\times 10^5\)


解题思路

考虑到主要的阈值\([B+1,C-1]\)中的最大值,一旦超过了这个值就只需要考虑是否大于\([C,D]\)中的最大值就好了。

那么我们考虑如何选取起点,首先我们显然不能超过\([C,D]\)中的最大值\(mx\),在这一情况下我们需要找到一个最大的位置小于\(mx\)且在它后面没有比\(mx\)大的数(否则就跳不过去了),这个过程我们用二分加\(ST\)表可以实现。

然后考虑选取起点如何跳跃,首先如果\([B+1,C-1]\)中的最大值\(lim\)远大于起点的话我们肯定是优先考虑跳左右两边高的那个点,这样肯定是最优的。所以我们在不大于\(lim\)的情况下肯定是选取这种跳法。对于这样的跳跃我们处理出一棵树然后在上面倍增即可。

然后当跳到最后一个小于\(lim\)的值时我们有两种方法,一种是继续这样跳此时我们的值大于\(lim\)了可以直接跳过\([B+1,C-1]\)但是需要判断这个值是否小于\(mx\)。(否则就顺便跳过了\([C,D]\))。

第二种方法是直接一直往右边跳直到到\([C,D]\)段,这个我们的处理方法可以每个点向它右边比它大的第一个点连边,然后\(lim\)肯定在起点到根的路径上,直接用深度减去即可。

记得判无解

时间复杂度\(O(n\log n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=2e5+10,T=18;
int n,q,h[N],p[N],l[N],r[N],lg[N];
int f[N][T],g[N][T],dep[N];
int RMQ(int l,int r){
if(l>r)return 0;int z=lg[r-l+1];
return max(f[l][z],f[r-(1<<z)+1][z]);
}
void init(int N,std::vector<int> H) {
n=N;h[0]=n+1;
for(int i=1;i<=n;i++)
h[i]=H[i-1],p[h[i]]=i,f[i][0]=h[i];
for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);
for(int i=1;i<=n;i++)l[i]=i-1,r[i]=i+1;
for(int i=1;i<=n;i++){
int x=p[i];
r[l[x]]=r[x];l[r[x]]=l[x];
g[x][0]=(h[l[x]]>h[r[x]])?l[x]:r[x];
}
for(int j=1;j<T;j++)
for(int i=1;i<=n;i++)
g[i][j]=g[g[i][j-1]][j-1];
for(int i=n;i>=1;i--)dep[i]=dep[r[i]]+1;
}
int minimum_jumps(int A,int B,int C,int D){
A++;B++;C++;D++;int l=A,r=B;
int lim=RMQ(B+1,C-1),zc=RMQ(C,D);
if(RMQ(B,C-1)>zc)return -1;
while(l<=r){
int mid=(l+r)>>1;
if(RMQ(mid,B)>zc)l=mid+1;
else r=mid-1;
}
int x=p[RMQ(l,B)],ans=0;
if(h[x]>lim)return 1;
for(int i=T-1;i>=0;i--)
if(h[g[x][i]]<lim)x=g[x][i],ans+=(1<<i);
if(g[x][0]&&h[g[x][0]]<zc&&h[x]<lim)ans+=2;
else ans+=dep[x]-dep[p[lim]]+1;
return ans;
}
//vector<int> H;
//int main()
//{
// scanf("%d%d",&n,&q);
// for(int i=0,x;i<n;i++)
// scanf("%d",&x),H.push_back(x);
// init(n,H);
// while(q--){
// int A,B,C,D;
// scanf("%d%d%d%d",&A,&B,&C,&D);
// printf("%d\n",minimum_jumps(A,B,C,D));
// }
// return 0;
//}

P7599-[APIO2021]雨林跳跃【二分,倍增,ST表】的更多相关文章

  1. 浅谈 倍增/ST表

    命题描述 给定一个长度为 \(n\) 的序列,\(m\) 次询问区间最大值 分析 上面的问题肯定可以暴力对吧. 但暴力肯定不是最优对吧,所以我们直接就不考虑了... 于是引入:倍增 首先,倍增是个什么 ...

  2. bzoj3277 串 (后缀数组+二分答案+ST表)

    常见操作:先把所有串都连到一起,但中间加上一个特殊的符号(不能在原串中/出现过)作为分割 由于全部的子串就等于所有后缀的所有前缀,那我们对于每一个后缀,去求一个最长的前缀,来满足这个前缀在至少K个原串 ...

  3. 【CSP膜你赛】柠檬的密码(manacher 二分 单调性 st表)

    题目描述 Lemon觉得他需要一个复杂的密码来保证他的帐号的安全.他经过多日思考,决定使用一个长度为奇数的回文串来作为他的密码.  但是这个回文串太长了,Lemon记不住,于是Lemon决定把它记在本 ...

  4. Codeforces 475D 题解(二分查找+ST表)

    题面: 传送门:http://codeforces.com/problemset/problem/475/D Given a sequence of integers a1, -, an and q ...

  5. [BZOJ3277/BZOJ3473] 串 - 后缀数组,二分,双指针,ST表,均摊分析

    [BZOJ3277] 串 Description 现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). Solution 首先将所有串连 ...

  6. 【BZOJ1047】[HAOI2007]理想的正方形 (倍增ST表)

    [HAOI2007]理想的正方形 题目描述 有一个\(a*b\)的整数组成的矩阵,现请你从中找出一个\(n*n\)的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: ...

  7. 2019.03.04 bzoj5308: [Zjoi2018]胖(二分答案+st表)

    传送门 想题5分钟调题两小时系列 其实还是我tcl 读完题之后自然会知道一个关键点能够更新的点是一段连续的区间,于是我们对于每个点能到的左右区间二分答案,用ststst表维护一下查询即可. 代码: # ...

  8. 2018.10.14 NOIP训练 直线(二分答案+st表+切比雪夫距离转化)

    传送门 二分答案好题. 这已经是当年普及组模拟时挖的坑了233. 这道题还是很不错的. 考虑把坐标系转个45度再操作. 为了不爆精度可以直接转切比雪夫距离. 然后就直接二分答案. 其中竖线就按二分的答 ...

  9. poj 3264 倍增 ST表

    #include<iostream> #include<cmath> using namespace std; ; int a[maxn]; ]; ]; int quick(i ...

随机推荐

  1. redis缓存穿透,缓存击穿,缓存雪崩

    缓存穿透 缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有.这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询).这样请求就会绕过 ...

  2. PostgreSQL隐藏字段

    1)创建了一个表 apple=# \d test_time Table "public.test_time" Column | Type | Modifiers --------+ ...

  3. mysql开启远程访问权限的设置

    MySql-Server 出于安全方面考虑默认只允许本机(localhost, 127.0.0.1)来连接访问. 所以必须给root修改可以远程访问的权限 1.在连接服务器后,操作mysql系统数据库 ...

  4. Linux第一个动态库

    动态库一般以.so结尾,就是shared object的意思. 其基本生成步骤为   ⑴编写函数代码   ⑵编译生成动态库文件,要加上 -shared 和 -fpic 选项 ,     库文件名以li ...

  5. HDFS简介及基本概念

    (一)HDFS简介及其基本概念   HDFS(Hadoop Distributed File System)是hadoop生态系统的一个重要组成部分,是hadoop中的的存储组件,在整个Hadoop中 ...

  6. QT中的对象模型――QPointer

    QPointer是一个模板类,为QObject对象提供了守卫指针(Guarded Pointer).什么是守卫指针?守卫指针QPointer<T>类似于普通C++指针T *,有且仅有一点不 ...

  7. C# 启动 Flask for Python

    概览 最近有个需求是通过c#代码来启动 python 脚本.嘿~嘿!!! 突发奇想~~既然可以启动 python 脚本,那也能启动 flask,于是开始着手操作. 先看gif图 准备 因为使用的是.N ...

  8. Java Web基础 --- Servlet 综述(理论篇)

    摘要: Web 技术成为当今主流的互联网 Web 应用技术之一,而 Servlet 是 Java Web 技术的核心基础.本文首先从请求/响应架构应用的大背景谈起 Servlet 的由来,明确 Ser ...

  9. Python - 面向对象编程 - 什么是 Python 类、类对象、实例对象

    什么是对象和类 https://www.cnblogs.com/poloyy/p/15178423.html Python 类 类定义语法 最简单的类定义看起来像这样 class ClassName: ...

  10. 30 道 Vue 面试题,内含详细讲解(涵盖入门到精通,自测 Vue 掌握程度)

    前言 本文以前端面试官的角度出发,对 Vue 框架中一些重要的特性.框架的原理以问题的形式进行整理汇总,意在帮助作者及读者自测下 Vue 掌握的程度.本文章节结构以从易到难进行组织,建议读者按章节顺序 ...