lca倍增演算法模板
1431: LCA 最近公共祖先
時間限制: 1 Sec 記憶體限制: 128 MB提交: 244 解決: 36
[提交][狀態]
題目描述
給一棵樹, 節點數為N(1 <= N <= 250,000), 和Q(0 <= Q <= 100,000)個詢問, 對於每個詢問求出所求兩點的最近公共祖先
輸入
第一行: 節點數N
以下N行, 第i + 1行: 點i的父親節點Father[i] (假定根的父親是0)
下一行為詢問數Q
每個詢問包含兩個整數i, j你的程式應按照詢問的次序回答出所求兩點的最近公共祖先
輸出
共N行, 第i行: 第i個詢問的答案
樣例輸入
12 0 1 1 1 2 2 3 3 8 8 9 10 5 5 12 12 7 9 12 10 12 12 12
樣例輸出
1
3
8
10
12
倍增演算法:主要分兩步。
第一步:將兩個節點"竄"到一個深度
第二步:兩個節點一起"竄"到他們的lca(最近公共祖先)。
'竄'的操作,如果你每個節點一下,一下,一下的竄,會非常慢。。所以就有了倍增,要一次竄2^n個節點。當然如果過頭了就少竄一點。如果你寫過01
揹包,它的思路和2進位制拆包很像。
看起來好像很簡單的樣子>-<程式碼如下(帶註釋)
#include<iostream> #include<cmath> #include<cstdio> #include<algorithm> #include<cstring> #include<cstdlib> #include<ctime> using namespace std; const int maxn=250020; int n,q; int g[100][100],ne,root; int p[maxn][20];//p[i][j]表示i結點的第2^j祖先 int deep[maxn];//i的深度 int use[1000][1000]; void build(int x)//處理樹深度 { for(int i=1;i<=n;i++) if(g[x][i]==1) { deep[i]=deep[x]+1; p[i][0]=x; g[x][i]=g[i][x]=0; build(i); } } void pre()//處理祖先 { int i,j; for(j=1;(1<<j)<=n;j++) for(i=1;i<=n;i++)//! !j在i前面!!記住 if(p[i][j-1]!=-1) p[i][j]=p[p[i][j-1]][j-1];//i的第2^j祖先就是i的第2^(j-1)祖先的第2^(j-1)祖先 } int lca(int a,int b)//最近公共祖先 { //使a,b兩點的深度相同 int i,j; if(deep[a]<deep[b])swap(a,b); for(i=0;(1<<i)<=deep[a];i++); i--; for(j=i;j>=0;j--) if(deep[a]-(1<<j)>=deep[b]) a=p[a][j]; if(a==b)return a; //倍增法,每次向上進深度2^j,找到最近公共祖先的子結點 for(j=i;j>=0;j--) { if(p[a][j]!=-1&&p[a][j]!=p[b][j])//!! { a=p[a][j]; b=p[b][j]; } } return p[a][0];//即正好竄到兩個子樹上,最近祖先為它的j=0的祖先 } int main() { cin>>n>>q; for(int i=1;i<=n;i++) { int a,b; cin>>a>>b; g[a][b]=g[b][a]=1; } p[1][0]=-1; deep[1]=1; build(1); pre(); for(int i=1;i<=q;i++) { int x,y; scanf("%d%d",&x,&y); printf("%d\n",lca(x,y)); } return 0; }
相關推薦
lca倍增演算法模板
1431: LCA 最近公共祖先 時間限制: 1 Sec 記憶體限制: 128 MB提交: 244 解決: 36 [提交][狀態] 題目描述 給一棵樹, 節點數為N(1 <= N &
lca倍增演算法學習記錄
找最近公共父節點這問題很容易想到讓兩節點一起往上走最後相遇,但這樣的dfs顯然很慢,於是就需要倍增。就是用二進位制的思維,以1,2,4,8等2的階層步長接近答案,比一步一步向上要快很多。 所以要dfs出來點的2^k的父親節點與該節點的深度。 找lca時先將下
LCA RMQ演算法模板
題目:HDU 3078 Network 主要貼一下LCA RMQ的演算法模板,供以後回憶 #include <iostream> #include <cstdio> #include <cstdlib> #include <alg
lca倍增演算法
HDU2586 要注意只有簡單邊相連的圖是一棵樹,樹有n-1條邊 倍增之前要先存雙向邊,以任意頂點為根(比如1)dfs遍歷確定樹。 倍增前求f[i,j]時先賦值為-1便於判斷f[ij-1]祖先存不存在 倍增時先將兩個點調至同一高度(注意最後的微調每次只上升一個高度) pro
POJ-1330-Nearest Common Ancestors(LCA+倍增模板題)
題目連結:http://poj.org/problem?id=1330 Description A rooted tree is a well-known data structure in computer science and engineering. An example is sh
LCA-Tarjan,RMQ,倍增演算法超詳細原理講解+python實踐(Lowest Common Ancestor of a Binary Tree)
最近公共祖先演算法: 通常解決這類問題有兩種方法:線上演算法和離線演算法 線上演算法:每次讀入一個查詢,處理這個查詢,給出答案 離線演算法:一次性讀入所有查詢,統一進行處理,給出所有答案 我們接下來介紹一種離線演算法:Tarjan,兩種線上演算法:RMQ,倍增演算法 Tarjan
最近公共祖先(LCA) 【倍增演算法】
題目連結:洛谷-P3379 ## **題目描述**: 如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。 思路 這是一個裸的LCA問題,即求書上兩個節點的最近公共祖先。 我們可以用樹上倍增來做; 當然,在做之前我們假設不知道該演算法。那麼我們如何來做
DP之倍增演算法解決LCA問題
LCA,最近公共祖先,也就是樹上兩個節點的相同的祖先裡距離它們最近的(也就是深度最深的)。倍增演算法用於解決LCA問題的線上查詢。 比如要找x和y的LCA,一般會怎麼做? 首先是暴力。一種是DFS遍歷說有點,無需預處理,查詢是O(n)的。還有一種暴力是先一步一步將x和y提到同一高度,然後
[HDU2586] How far away ?{LCA.tarjan演算法/倍增演算法}
文章目錄 題目 解題思路 程式碼`倍增(TLE)` 程式碼`tarjan演算法(AC)` $tanjan$演算法本質上是使用並查集對“向上標記法”的優化 題目 http://acm.hdu.edu.cn
LCA 倍增模板
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int ,int > pii; const int N =100010; const in
LCA演算法模板
#include<string> #include<cstring> #include<iostream> #include<cstdio> #define LL long long using namespace
LCA(最近公共祖先)Tarjan演算法模板
#include <iostream> #include <cstdio> #include <cstring> #include <vector> using namespace std; /** 1.dfs 2.
最近公共祖先LCA---線上倍增演算法
線上求LCA,多次詢問。倍增演算法時間複雜度為。 1、dfs求每個節點所在層數 void dfs(int u,int root,int d) { int i; depth[u]=d; fa[u][0]=root;//初始化 int
【模板】LCA Tarjan演算法 (模板題:洛谷P3379)
題目描述 如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。 輸入輸出格式 輸入格式: 第一行包含三個正整數N、M、S,分別表示樹的結點個數、詢問的個數和樹根結點的序號。 接下來N-1行每行包含兩個正整數x、y,表示x結點和y結點之間有一條直接連線的邊
求LCA——最近公共祖先 倍增演算法
LCA是啥呢,LCA就是一棵樹裡兩個節點的最近公共祖先,如下圖 2號節點和3號節點的LCA就是1, 5號節點和11號節點的LCA就是2,8號節點和4號節點的lca就是4 那麼怎麼求LCA呢。首先要建樹,然後最容易想到的就是兩個節點一起向上跳,第一個相遇的節點就是LCA
HDU 4757 Tree (倍增演算法求LCA + 可持久化Trie樹)
題目大意: 就是現在給出一棵樹, 結點個數不超過10W, 每個節點上有一個不超過2^16的非負整數, 然後10W次詢問, 每次詢問兩個節點的路徑上的所有數中異或上給出的數的最大值 大致思路: 剛開始做這個題想的是樹鏈剖分之後用線段樹套Trie樹來做...結果悲劇地MLE了
LCA(最近公共祖先)倍增演算法
最近公共祖先有多種演算法 如倍增,RMQ,樹鏈剖分等 這裡先介紹倍增演算法 預處理複雜度nlog(n); 詢問複雜度log(n); 倍增與二進位制息息相關 與分塊的演算法有些相似之處 使用倍增演算法時開一個fa[n][S]陣列 fa[i][j]
Algorithm---LCA(倍增演算法)
deep[i] 表示 i節點的深度, fa[i,j]表示 i 的 2^j (即2的j次方) 倍祖先,那麼fa[i , 0]即為節點i 的父親,然後就有一個遞推式子: fa[i,j]= fa [ fa [i,j-1] , j-1 ] 可以這樣理解: 設tmp = fa [
UVa 11149 矩陣的冪(矩陣倍增法模板題)
ble 化簡 .cn target ans txt put std net https://vjudge.net/problem/UVA-11149 題意: 輸入一個n×n矩陣A,計算A+A^2+A^3+...A^k的值。 思路: 矩陣倍增法。
(樹形dp+LCA倍增法)CSU 1915 - John and his farm
const http 題解 def iostream clu algo farm john 題意: 有一個棵樹,現在讓你找兩個點連接起來,這樣必然成為一個環,現在要求這些環長度的期望,也就是平均值。 分析: 第一次做LCA題,做多校的時候,瞎幾把找了模板敲,敲了個八九