1. 程式人生 > >Gym 102091A: Flying Squirrel(RMQ)

Gym 102091A: Flying Squirrel(RMQ)

include clas height nlog can 給定 inf info nlogn

技術分享圖片

題意:如圖,有N個柱子,每次我可以從高柱子X到低柱子Y,而且需要滿足中間的柱子都小於X的高度。

思路:現在有Q次詢問,每次給定(X,Y),(如果ht[X]<ht[Y],則交換XY),問X為起點,Y為終點的最長路徑。 如果Y為0,你可以選擇任一點為終點。

每次我們把當前dfs的區間最高的幾個柱子(假設高度為H)抽出來,它們把當前區間劃分為了幾個小區間,可以把這些高的柱子看成根,那麽被夾在中間的區間就是子樹,再去dfs深入中間的區間即可。 最後假如要從X到Y,如果它們之間沒有更高的,答案就是深度差

由於每個柱子只被當成一次根,所的復雜度是O(N)的,加上RMQ找區間最大值,總的時間是O(NlogN)的。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=200010;
int h[maxn],dep[maxn],ans[maxn];
int mx[20][maxn],Log[maxn];
int Max(int a,int b){ return h[a]>=h[b]?a:b;}
int find(int L,int R)
{
    int k=Log[R-L+1];
    return Max(mx[k][L],mx[k][R-(1
<<k)+1]); } int solve(int L,int R,int d) { if(L>R) return -1; int p=find(L,R); dep[p]=d; ans[p]=solve(L,p-1,d+1)+1; int res=ans[p]; while(p<R){ int q=find(p+1,R); if(h[q]!=h[p]) break; dep[q]=d; int t=solve(p+1,q-1,d+1)+1; res
=max(res,t); ans[p]=max(ans[p],t); ans[q]=t; p=q; } ans[p]=max(ans[p],solve(p+1,R,d+1)+1); res=max(res,ans[p]); return res; } int main() { int N,M,L,R; scanf("%d%d",&N,&M); rep(i,1,N) scanf("%d",&h[i]); Log[0]=-1; rep(i,1,N) Log[i]=Log[i>>1]+1; rep(i,1,N) mx[0][i]=i; for(int i=1;(1<<i)<=N;i++) for(int j=1;j+(1<<i)-1<=N;j++) mx[i][j]=Max(mx[i-1][j],mx[i-1][j+(1<<(i-1))]); solve(1,N,0); rep(i,1,M){ scanf("%d%d",&L,&R); if(h[L]<h[R]) swap(L,R); if(!R) printf("%d\n",ans[L]); else { if(L==R) puts("0"); else { int p; if(L<R) p=find(L+1,R); else p=find(R,L-1); if(h[p]>=h[L]) puts("0"); else printf("%d\n",dep[R]-dep[L]); } } } return 0; }

Gym 102091A: Flying Squirrel(RMQ)