P7599 [APIO2021] 雨林跳跃
作者:互联网
封闭道路的题解呢?
考虑 A = B , C = D A=B,C=D A=B,C=D
只需要从 A A A开始每一步都跳最大的那个就好了!如果能跳到,说明 m a x [ B , C − 1 ] < m a x [ C , D ] max[B,C-1]< max[C,D] max[B,C−1]<max[C,D]
否则我们要么一步跳过去,要么中途跳到 B , C − 1 B,C-1 B,C−1某个数然后自闭掉
那么我们只需要每次跳小于 max [ C , D ] \max[C,D] max[C,D]范围内最大的一个就好了
然后考虑 A ≠ B A\not = B A=B
我们想法是选择一个最大的 P ∈ [ A , B ] P\in [A,B] P∈[A,B],然后发现如果 P > max [ C , D ] P>\max [C,D] P>max[C,D]就彻底完蛋了…
于是发现我们如果有一个值大于 max [ C , D ] \max[C,D] max[C,D],这个值前面的所有数都达不到目标点了…
然后我们相当于在这个区间的一个后缀中找到一个最大的 < max [ C , D ] <\max[C,D] <max[C,D] 的数
线段树二分就好了!寻找这个区间最后一个大于等于x的值,然后再在这个值前面查询一个最大值的位置就好了
然后考虑 C ≠ D C\not =D C=D
我们发现有效的值似乎只有 max [ C , D ] \max [C,D] max[C,D]
但是考虑我们可能没有跳到最大值的时候就已经跳过去了…
于是发现我们还是要从 [ B , C − 1 ] [B,C-1] [B,C−1]这个区间入手,我们第一次跳到这个区间的最大值的时候就结束了!因为我们下一步一定可以跳进目标区间!
于是考虑我们现在完全将所有问题都规约到了 A = B , C = D A=B,C=D A=B,C=D
如何解决这个问题的最小步数?
首先,第一个数在树上倍增,找到第一个小于等于他的最大的数,满足这个数再向左边跳就跳到大于它的位置了,如果直接跳到那还挺好的
然后,第二个树在序列上倍增,相当于我们每个数只能向右侧跳,然后计算这样跳到它的最小步数
就做完了,复杂度一个 log \log log
注意我们可能一步跳到 [ C , D ] [C,D] [C,D]的不只有 [ B , C − 1 ] [B,C-1] [B,C−1]的max,还有这个max值的前驱我们可能一步跳到他
特别的,你会发现一开始找到的数就能一步跳过去就直接选择那个数就好啦!
P7598 [APIO2021] 六边形领域
转换成网格之后一三象限距离为切比雪夫距离二四象限曼哈顿距离
然后转换方法为六个方向变成上下左右右上方左下方
并且一个正方形要变成两部分!就可以对应原来的六边形网格了
#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstring>
using std::max;
using std::min;
void init(int N, std::vector<int> H);
int minimum_jumps(int A, int B, int C, int D);
const int MAXN=3e5+7;
const int B=19;
int n;
int lg2[MAXN],f[B][MAXN],a[MAXN],g[B][MAXN],p[B][MAXN];
inline int qrym(int l,int r) {
int tmp=lg2[r-l+1];
return max(f[tmp][l],f[tmp][r-(1<<tmp)+1]);
}
int home[MAXN],nxt[MAXN],to[MAXN],ccnt,pre[MAXN],suf[MAXN];
inline void ct(int x,int y) {
ccnt++;
nxt[ccnt]=home[x];
to[ccnt]=y;
home[x]=ccnt;
}
inline void dfs(int u) {
for(int i=1; i<B; ++i) {
g[i][u]=g[i-1][g[i-1][u]];
}
for(int i=home[u]; i; i=nxt[i]) {
dfs(to[i]);
}
return ;
}
inline void dfs2(int u) {
for(int i=1; i<B; ++i)p[i][u]=p[i-1][p[i-1][u]];
for(int i=home[u]; i; i=nxt[i])dfs2(to[i]);
return ;
}
inline void init2() {
pre[1]=0;
for(int i=2; i<=n; ++i) {
int l=1,r=i-1,mid,ans=0;
while(l<=r) {
mid=(l+r)>>1;
if(qrym(mid,i-1)>=a[i]) {
l=mid+1;
ans=mid;
} else {
r=mid-1;
}
}
pre[i]=ans;//前面第一个大于它的位置
}
a[n+1]=a[0]=0;
suf[n]=n+1;
for(int i=n-1; i>=1; --i) {
int l=i+1,r=n,mid,ans=n+1;
while(l<=r) {
mid=(l+r)>>1;
if(qrym(i+1,mid)>=a[i]) {
r=mid-1;
ans=mid;
} else {
l=mid+1;
}
}
suf[i]=ans;
}
int mx=0;
for(int i=1; i<=n; ++i) {
if(a[i]>a[mx])mx=i;
if(a[suf[i]]>a[pre[i]]) {
g[0][i]=suf[i];
ct(suf[i],i);
} else if(a[suf[i]]<a[pre[i]]) {
g[0][i]=pre[i];
ct(pre[i],i);
}
}
dfs(mx);
ccnt=0;
memset(home,0,sizeof(home));
for(int i=1; i<=n; ++i) {
p[0][i]=suf[i];
ct(suf[i],i);
}
dfs2(n+1);
return ;
}
inline int getpos1(int L,int R,int p) {
int mid,ans=0;
while(L<=R) {
mid=(L+R)>>1;
if(qrym(mid,R)>=p) {
ans=mid;
L=mid+1;
} else {
R=mid-1;
}
}
return ans;
}
inline int getpos2(int L,int R,int p) {
int mid,ans=0;
while(L<=R) {
mid=(L+R)>>1;
if(qrym(L,mid)>=p) {
ans=mid;
R=mid-1;
} else {
L=mid+1;
}
}
return ans;
}
void init(int N, std::vector<int> H) {
n=N;
for(int i=2; i<=N; ++i) {
lg2[i]=lg2[i>>1]+1;//我太菜了
}
for(int i=1; i<=N; ++i) {
a[i]=f[0][i]=H[i-1];
}
for(int i=1; i<B; ++i) {
for(int j=1; j<=N; ++j) {
if(j+(1<<i)-1<=N) {
f[i][j]=max(f[i-1][j],f[i-1][j+(1<<(i-1))]);
}
}
}
init2();
return ;
}
inline int calc(int x,int y) {
int ret=0;
for(int i=B-1; i>=0; --i) {
if(a[g[i][x]] && a[g[i][x]]<=a[y]) {
ret+=(1<<i);
x=g[i][x];
}//先跳大的qwq
}
if(x==y)return ret;
for(int i=B-1; i>=0; --i) {
if(a[p[i][x]] && a[p[i][x]]<=a[y]) {
ret+=(1<<i);
x=p[i][x];
}//再跳小的qwq
}
return ret;
}
int minimum_jumps(int A, int B, int C, int D) {
++A,++B,++C,++D;
if(B>=C)return 0;
int Lim=qrym(B,C-1);//QAQ!
int mx2=qrym(C,D);
if(Lim>mx2)return -1;
int l=A,r=B,mid,ans=A-1;//QAQ
while(l<=r) {
mid=(l+r)>>1;
if(qrym(mid,B)>=mx2) {//???
ans=mid;
l=mid+1;
} else {
r=mid-1;
}
}
if(ans==B)return 1;//一次杀掉了
int mx1=qrym(ans+1,B);
if(mx1>Lim)return 1;
int u=getpos1(ans+1,B,mx1);//直接gepos
int v=getpos2(B,C-1,Lim);//u->v
int ans1=calc(u,v);
int ans2=1e9;
if(pre[v] && a[pre[v]]<mx2)ans2=calc(u,pre[v]);
ans1=min(ans1,ans2)+1;
return ans1;
}
标签:return,qrym,int,max,P7599,mid,雨林,APIO2021,ans 来源: https://blog.csdn.net/xiaxiaoguang_/article/details/118555393