給定一棵有n個結點的樹,q個詢問,每次詢問點x到點y亮點之間的距離
第一行乙個n,表示有n個節。
接下來有n-1行,每行2個整數x,y表示x,y之間有一條連邊。
然後乙個整數q,表示有q次詢問,接下來q行每行2個整數x,y表示詢問x到y的距離。
輸出q行,每行表示每個詢問的結果
6
1 21 3
2 42 5
3 62
2 65 6
3
4
倍增法是由幾個步驟配合完成的:
首先我們對輸入的資料進行建樹,然後對樹進行深度遍歷得到每個節點的深度以及記錄它們的父節點。
然後我們用乙個特殊的陣列st[i][j]表示節點i上跳2^j次後得到的節點,其中st[i][0]表示第i個節點的父節點,有乙個公式是需要理解的,st[ i ][ j ]=st[ st[i][j-1] ][ j-1 ],意思就是第i個節點上跳2^j個節點等於i節點向上跳2^(j-1)的這個節點向上跳2^(j-1)次方(2^j=2^(j-1)+2^(j-1)),j的取值範圍為[1,log2 n]。
接著就是求兩個節點的最近公共祖先,首先我們要把兩個節點調整到同一深度,具體做法是是使深度大的上跳;當到達同一深度後同時上跳,直到上跳得到的節點相同,那麼這個節點就是它們的最近公共祖先,在程式中用get_lca()來實現。
這題首先求出兩個節點的lca,然後x,y兩點之間的最短路徑就是x->xy的最近公共祖先->y,它們的距離就等於x的深度加上y的深度減去兩倍的公共祖先的深度。
關於鏈式前向星,它是通過儲存邊來儲存一顆樹的,首先用num_edge記錄邊的編號(順序無關)。然後有乙個first[i]陣列,它儲存的是與i點相連的已加入的最後一條邊的num_edge編號(為什麼這樣儲存後面說),然後開乙個結構體edge,next表示下一條邊的num_edge編號,to表示這條邊到達的點。
儲存的方法是:每加入一條邊(i,j),就把這條邊加到i、j鍊錶的首部,並更新first[i],first[j]陣列。
廣度優先遍歷的方法就是,對於與i相連的所有點,找到最後一次加入的邊的num_edge編號,i是邊的起點(不是真正意義的起點),edge[i].to是邊的終點,通過訪問edge[i].next找到下一條與i相連的邊的編號繼續訪問。
而深度優先遍歷則是找到某條邊的終點(不是真正意義的終點),將這個終點作為起點,繼續訪問它的終點迴圈下去。
#include#includeusing namespace std;
const int maxn=4e5+10;
int num_edge=0,father[maxn],dep[maxn],st[maxn][25];
int first[maxn];//x點最後一條邊的編號
struct edge
edge[maxn*2];
void add_edge(int from,int to)
void dfs(int x,int fa)
}int get_lca(int x,int y)
} return father[x];
}int main()
dep[1]=1;//選作為根節點
dfs(1,0);
for(int i=1;i<=n;i++)
st[i][0]=father[i];//向上跳一格就是自己的父節點
for(int j=1;j<=20;j++)
for(int i=1;i<=n;i++)
st[i][j]=st[ st[i][j-1] ][ j-1 ];
scanf("%d",&q);
while(q--)
return 0;
}
入門者筆記 LCA(鏈式前向星)
lca least common ancestors 即最近公共祖先,是指在有根樹中,找出某兩個結點u和v最近的公共祖先。所謂倍增,就是按2的倍數來增大,也就是跳 1,2,4,8,16,32 不過在這我們不是按從小到大跳,而是從大向小跳,即按 32,16,8,4,2,132,16,8,4,2,1來跳...
鏈式前向星 鄰接表 頭插法
通過我的理解我覺得鏈式前向星就是一種用鄰接表存圖的方式,我們知道資料結構中向鄰接表中插入元素有兩種方式尾插法和頭插法.如果我們用stl中vector模擬鄰接表的話,當我們插入元素的時候,很顯然它是用尾插法插入的元素.今天我就來說一下用頭插法來實現插入,也就是上面所說的鏈式前向星.使用陣列的方式來實現...
走進鏈式前向星的秘密
前言 之前學鏈式前向星的時候,發現網上的部落格一點都不友好 所以今天花一點一時間來擼一擼鏈式前向星 d 二傻子般的微笑 正文 鏈式前向星的主要就是下面這幾行了 1 void add int u,int v,int w 2介紹一下 第乙個出場的是edge.c 權重 好的,我們看到緊隨其後的是edge....