日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P7599-[APIO2021]雨林跳跃【二分,倍增,ST表】

發布時間:2023/12/3 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P7599-[APIO2021]雨林跳跃【二分,倍增,ST表】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

題目鏈接:https://www.luogu.com.cn/problem/P7599


題目大意

nnn棵樹,在某棵樹上時可以選擇向左右兩邊第一棵比它高的樹跳,現在qqq次詢問從[A,B][A,B][A,B]中某個點出發跳到[C,D][C,D][C,D]中某個點的最少次數。

1≤n≤2×1051\leq n\leq 2\times 10^51n2×105


解題思路

考慮到主要的閾值[B+1,C?1][B+1,C-1][B+1,C?1]中的最大值,一旦超過了這個值就只需要考慮是否大于[C,D][C,D][C,D]中的最大值就好了。

那么我們考慮如何選取起點,首先我們顯然不能超過[C,D][C,D][C,D]中的最大值mxmxmx,在這一情況下我們需要找到一個最大的位置小于mxmxmx且在它后面沒有比mxmxmx大的數(否則就跳不過去了),這個過程我們用二分加STSTST表可以實現。

然后考慮選取起點如何跳躍,首先如果[B+1,C?1][B+1,C-1][B+1,C?1]中的最大值limlimlim遠大于起點的話我們肯定是優先考慮跳左右兩邊高的那個點,這樣肯定是最優的。所以我們在不大于limlimlim的情況下肯定是選取這種跳法。對于這樣的跳躍我們處理出一棵樹然后在上面倍增即可。

然后當跳到最后一個小于limlimlim的值時我們有兩種方法,一種是繼續這樣跳此時我們的值大于limlimlim了可以直接跳過[B+1,C?1][B+1,C-1][B+1,C?1]但是需要判斷這個值是否小于mxmxmx。(否則就順便跳過了[C,D][C,D][C,D])。

第二種方法是直接一直往右邊跳直到到[C,D][C,D][C,D]段,這個我們的處理方法可以每個點向它右邊比它大的第一個點連邊,然后limlimlim肯定在起點到根的路徑上,直接用深度減去即可。

記得判無解

時間復雜度O(nlog?n)O(n\log n)O(nlogn)


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表】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。