把一步一步往上爬變成一次一次向前跳,從\(o(n)->o(log_)\)的蛻變,可以解決很多問題。
\[anc[i][k]=anc[anc[i][k-1]][k-1]
\]就這麼一行。
我的\(2^\)級祖先就是我\(2^\)級祖先的\(2^\)級祖先。
就憑這句話,就可以解決很多問題了。
洛谷p1613跑路
小a的工作不僅繁瑣,更有苛刻的規定,要求小a每天早上在6:00之前到達公司,否則這個月工資清零。可是小a偏偏又有賴床的壞毛病。於是為了保住自己的工資,小a買了乙個十分牛b的空間跑路器,每秒鐘可以跑2^k千公尺(k是任意自然數)。當然,這個機器是用longint存的,所以總跑路長度不能超過maxlongint千公尺。小a的家到公司的路可以看做乙個有向圖,小a家為點1,公司為點n,每條邊長度均為一千公尺。小a想每天能醒地盡量晚,所以讓你幫他算算,他最少需要幾秒才能到公司。資料保證1到n至少有一條路徑。
maxlongint是\(2147483647\)。
由於\(n\)只有50,於是就愉悅地用矩陣。
\(t[i][j][k]\) 表示\(i,j\)之間有沒有長度為\(2^\)的邊。
\(dis[i][j]\) 表示\(i,j\)之間的距離。
先處理可以用加速器的情況,在跑floyd。
#includeconst int maxn=50+3;
bool t[maxn][maxn][35];
int dis[maxn][maxn];
int main()
for(int k=1;k<=31;k++)
for(int g=1;g<=n;g++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(t[i][g][k-1] && t[g][j][k-1])
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=std::min(dis[i][j],dis[i][k]+dis[k][j]);
printf("%d\n",dis[1][n]);
}
直接明示。
洛谷p3379【模板】最近公共祖先(lca)
倍增求lca算是最簡單的應用了吧。
原理就是那一行**。
向上跳的方法有多種,可以二進位制拆位,也可以算\(log_\)
#include#include#include#includeconst int maxn=5e5+5;
struct edge e[maxn<<1];
int h[maxn],tot;
void add_edge(int u,int v)
// 2^19 > maxn
int n,m,root;
int anc[maxn][20],lg[maxn],dep[maxn];
void dfs(int nd,int p)
int main() \)級祖先間的路徑最小限重是多少。
於是就解決了。
#include#include#include#include#includeconst int maxn=1e4+5;
const int maxm=5e4+5;
const int oo=0x3f3f3f3f;
int read()
//graph
struct edge e[maxn<<1];
int h[maxn],tot,whi[maxn];
void add_edge(int u,int v,int f)
//build max tree
struct edg e[maxm];
int fa[maxn];
int find(int x)
bool cmp(const edg &a,const edg &b)
//lca
int anc[maxn][23],dep[maxn];
int val[maxn][23];
bool vis[maxn];
void dfs(int nd)
return ;
}int n,m;
int lg[maxn];
int lca(int x,int y)
if(x==y) return ans;
for(int k=lg[dep[x]];~k;k--) if(anc[x][k]!=anc[y][k])
return std::min(ans,std::min(val[x][0],val[y][0]));
}int main()
for(int i=1;i<=n;i++)
if(!vis[i])
for(int k=1;k<=20;k++)
for(int i=1;i<=n;i++)
for(int i=1;i<=n;i++)
lg[i]=lg[i-1]+(1《如果不是看演算法標籤,或許我完全想不到倍增這種做法,但不管怎樣,還是總結一下。
常見題型:
lca其實最重要的是多做題是吧。帶\(2^\)的計算
......
對著那個式子一直想一直想。
或許吧。。。
LCA 二分 倍增
兩個最近的點u和v的最近的公共的祖先稱為最近公共祖先 lca 普通的lca演算法,每算一次lca的時間複雜度為線性o n 這裡講lca 二分的方法。首先對於任意的節點v,利用其父節點的資訊,可以通過par2 v par par v 得到向上走兩步的節點。依此資訊可以通過par4 v par2 par...
模板 二分 倍增及其應用
給定陣列 和 數字t,求最大位置k 滿足 sum 1 k t 最簡單的想法就是 字首和 二分,每次查詢時間複雜度log n 對於數列最左端的資料沒有必要 這裡的倍增可以理解為二分的改良優化版,設k點為0,p點為1 1.每次試從當前點k往後加p個數是否小於t 以log速度快速使k逼近答案點 2.隨後再...
《ACM程式設計》 Problem M 二倍問題
題意 描述作為算術能力計畫的一部分,您的學生將獲得2至15個唯一正整數的隨機生成列表,並要求確定每個列表中有多少專案是同一列表中的其他專案的兩倍。你需要乙個程式來幫助你評分。這個程式應該能夠掃瞄列表並輸出每個列表的正確答案。例如,給出列表 1 4 3 2 9 7 18 22 你的程式應該回答3,因為...