POJ - 1330 Nearest Common Ancestors(树上倍增/树链剖分求LCA)
生活随笔
收集整理的這篇文章主要介紹了
POJ - 1330 Nearest Common Ancestors(树上倍增/树链剖分求LCA)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
題目鏈接:點(diǎn)擊查看
題目大意:給出一棵有根樹(shù),我們需要求出兩個(gè)點(diǎn)的lca
題目分析:因?yàn)轭}目說(shuō)了是有根樹(shù),所以我們?cè)诮▓D的時(shí)候直接建有向圖就好了,并且記錄一下每個(gè)點(diǎn)的入度,建完圖后找一下入度為0的點(diǎn),就是根節(jié)點(diǎn)了,然后建樹(shù),就可以直接套模板求lca了,這里掛兩個(gè)模板,一個(gè)是樹(shù)上倍增,一個(gè)是樹(shù)鏈剖分,都寫(xiě)了一下練練手:
樹(shù)上倍增:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e4+100;int n;int limit;int in[N];vector<int>node[N];int dp[N][20];int deep[N];void dfs(int u,int f,int dep) {deep[u]=dep;dp[u][0]=f;for(int i=1;i<=limit;i++)dp[u][i]=dp[dp[u][i-1]][i-1];for(int i=0;i<node[u].size();i++){int v=node[u][i];if(v==f)continue;dfs(v,u,dep+1);} }int LCA(int x,int y) {if(deep[x]<deep[y])swap(x,y);for(int i=limit;i>=0;i--)if(deep[x]-deep[y]>=(1<<i))x=dp[x][i];if(x==y)return x;for(int i=limit;i>=0;i--)if(dp[x][i]!=dp[y][i]){x=dp[x][i];y=dp[y][i];}return dp[x][0]; }void init() {for(int i=1;i<=n;i++){node[i].clear();in[i]=0;}limit=log2(n)+1; }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);int w;scanf("%d",&w);while(w--){scanf("%d",&n);init();for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);node[u].push_back(v);in[v]++;}for(int i=1;i<=n;i++)if(!in[i]){dfs(i,-1,0);break;}int u,v;scanf("%d%d",&u,&v);printf("%d\n",LCA(u,v));}return 0; }樹(shù)鏈剖分:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e4+100;int n;int in[N];vector<int>node[N];int deep[N],fa[N],son[N],num[N];//深度、父節(jié)點(diǎn)、重兒子節(jié)點(diǎn)、子樹(shù)大小int top[N];//重鏈最上面的點(diǎn)void dfs1(int u,int f,int dep) {deep[u]=dep;fa[u]=f;son[u]=-1;num[u]=1;for(int i=0;i<node[u].size();i++){int v=node[u][i];if(v==f)continue;dfs1(v,u,dep+1);num[u]+=num[v];if(son[u]==-1||num[son[u]]<num[v])son[u]=v;} }void dfs2(int u,int f,int root) {top[u]=root;if(son[u]!=-1)dfs2(son[u],u,root);for(int i=0;i<node[u].size();i++){int v=node[u][i];if(v==f||v==son[u])continue;dfs2(v,u,v);} }int LCA(int x,int y) {while(top[x]!=top[y]){if(deep[top[x]]>deep[top[y]])//注意這里,deep里面還要套一個(gè)top,比較一下重鏈頂端的節(jié)點(diǎn)深度x=fa[top[x]];elsey=fa[top[y]];}return deep[x]>deep[y]?y:x; }void init() {for(int i=1;i<=n;i++){node[i].clear();in[i]=0;} }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);int w;scanf("%d",&w);while(w--){scanf("%d",&n);init();for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);node[u].push_back(v);in[v]++;}for(int i=1;i<=n;i++)if(!in[i]){dfs1(i,-1,0);dfs2(i,-1,i);break;}int u,v;scanf("%d%d",&u,&v);printf("%d\n",LCA(u,v));}return 0; }?
總結(jié)
以上是生活随笔為你收集整理的POJ - 1330 Nearest Common Ancestors(树上倍增/树链剖分求LCA)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: CodeForces - 979D Ku
- 下一篇: SPOJ - QTREE2 Query