RMQ問題
我們用dp[i][j]表示[i,i+2^j-1]區間的最大值,預處理的時候可以分兩個部分進行查詢最大值。
查詢區間[l,r]的最大值時我們只用查詢(l,l+2^s-1 )與(r-2^s+1,r),其中s=log2(r-l+1)就可以了,我們保證(l,r)的區間一定能覆蓋到且不會超出。
預處理時間複雜度O(nlogn),查詢時間複雜度O(1)
點選檢視程式碼
int a[N],dp[N],n;
void prep(){//預處理
for(int i=1;i<=n;i++){
cin>>a[i];
dp[i][0]=a[i];
}
for(int j=1;(j>>1)<=n;j++){
for(int i=1;i<=n;i++){
dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
}
int query(int l,int r){//查詢
int k=log2(r-l+1);
return max(dp[l][k],dp[r-(1<<k)+1][k]);
}
LCA
最近公共祖先簡稱 LCA(Lowest Common Ancestor)。兩個節點的最近公共祖先,就是這兩個點的公共祖先裡面,離根最遠的那個。
本題考慮倍增,用fa[x][i]表示節點x的第2^i個祖先,先使兩個節點到達同一深度,然後再同步從上往下跳。
點選檢視程式碼
int vis[N],dis[N],f[N][20];
vector<int>g[N];
void dfs(int x,int d){
vis[x]=1;
dis[x]=d;
for(int i=1;(1<<i)<=k;i++){
f[x][i]=f[f[x][i-1]][i-1];
}
for(int v:g[x]){
if(v==fa[x][0]) continue;
fa[v][0]=x;
dfs(v,d+1);
}
}
int lca(int x,int y){
if(dis[y]>dis[x]) swap(x,y);
int k=dis[x]-dis[y];
for(int i=1;(1<<i)<=k;i++){//對於xy距離k進行二進位制劃分
if(k&(1<<i)) x=fa[x][i];
}
if(x==y) return x;
for(int i=19;i>=0;i--){//從上往下跳,最後一定跳到LCA的下一層
if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
}
return fa[x][0];
}