例題:codevs 2370 小機房的樹
簡單來說就是給你乙個n個點的樹,每一條邊都有邊權。詢問有m次,每次給出兩個點,求他們之間的最小邊權和。
很容易想到用求樹上字首和和lca,先把兩個點跳到高度相同的地方,再一直往上跳,直到兩個點重合。因為乙個點乙個點的跳太慢了,所以我們倍增的跳來求lca。
令f[i][j]表示i號點往上跳2^j步的父親。
則 f[i][j]=f[f[i][j-1]][j-1];
這裡有兩個板子,思想都一樣。
板子一
1 #include2 #include3 #include4 #include5 #include6using
namespace
std;78
intn,m,u,v,c,cnt;
9int sum[50010],deep[50010],fa[50010][30],first[50010],next[100020
];10
struct
maplerode[100020
];13
14void build(int f,int t,int d) //
注意雙向建邊15;
17 next[cnt]=first[f];
18 first[f]=cnt;19}
20void dfs(int f,int t,int d) //
dfs處理出樹
2129
void done() //
預處理倍增跳的fa
3035
int lca(int x,int
y)36
43if(x==y) return
x;44
for(int i=log2(n);i>=0;--i) //
一起往上跳
45if(fa[x][i]!=fa[y][i])
46 x=fa[x][i],y=fa[y][i];
47return fa[x][0
];48}49
intmain()
5058 dfs(0,0,0
);59
done();
60 scanf("
%d",&m);
61while(m--)
6266
return0;
67 }
板子二
1 #include2 #include3 #include4 #include5 #include6using
namespace
std;78
intn,u,v,c,m;
9int first[150010],next[150010],fa[150010][30],deep[150010
],cnt;
10int de[60000
];11
struct
maplerode[150010
];14
15void done(int f,int t,int
v)16
26void build(int f,int t,int
d)27
;29 next[cnt]=first[f];
30 first[f]=cnt; 31}
32int lca(int x,int
y)33
42if(x==y) return
x;43
for(int i=log2(n);i>=0;--i)
44if(fa[x][i]!=fa[y][i])
45 x=fa[x][i],y=fa[y][i];
46return fa[x][0
];47}48
49int
main()
5060 done(0,0,0
);61 scanf("
%d",&m);
62while(m--)
6367
return0;
68 }
學習筆記 lca 倍增
求一棵樹上兩個節點的最近公共祖先有兩種演算法 tarjan 離線 這篇博文只介紹倍增的寫法.f i j 表示節點 i 的祖先中,與節點 i 距離為 2 j 的節點編號.那麼 f i j beginroot i root father i j 0,i not root f i j f f i j 1 ...
LCA 倍增 學習小結
lca問題,即lowest common ancestor 最近公共祖先 lca問題有很多解法,比如 暴力解法 分塊解法 倍增演算法 tarjan演算法 lct演算法 在這裡呢,我們只討論倍增 倍增演算法其實是一種類似於dp的實現 pa i j p a i j 表示i號節點的2j 2 j個父親 pa...
倍增LCA複習
時間過去了如此之久,我連倍增lca都不怎麼記得了,要粗事啊。首先預處理層數和每個節點的父親,然後預處理p陣列,p i,j 表示i向上第2 j個祖先。最後對於每個詢問x,y先把x,y變成同一層數的 x或y向上走直到兩個層數相等 然後x,y同時向上走,直到x和y的父親相同位置。自 1.dfs預處理出所有...