P3379 【模板】最近公共祖先(LCA)(倍增LCA)
题目链接:https://www.luogu.org/problem/P3379
题目大意:
给一棵以s为根的无向树,回答m个询问,回答出a和b最近的公共祖先。
解题报告:
倍增LCA的模板题,用一个数组 f [i] [j]表示i结点的第$2^{j}$个祖先。显然,一个点的祖先是f[i][0],对于当前点的第$2^{j}$个祖先的第$2^{j}$个祖先,等于当前点的第$2^{j+1}$个祖先,因为$2^{j}+2^{j}=2^{j+1}$。所以有递推式$f[i][j]=f[f[i][j-1]][j-1]$
还有一个常数优化是打表预处理出log2(i)+1的值。
AC代码:
1 #include<vector> 2 #include<cstdio> 3 #include<iostream> 4 #include<cmath> 5 #include<queue> 6 #include<stack> 7 #include<cmath> 8 #include<algorithm> 9 #define numm ch-48 10 #define pd putchar(' ') 11 #define pn putchar('\n') 12 #define pb push_back 13 #define fi first 14 #define se second 15 #define fre1 freopen("1.txt","r",stdin) 16 #define fre2 freopen("2.txt","w",stdout) 17 using namespace std; 18 template <typename T> 19 void read(T &res) { 20 bool flag=false;char ch; 21 while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true); 22 for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm); 23 flag&&(res=-res); 24 } 25 template <typename T> 26 void write(T x) { 27 if(x<0) putchar('-'),x=-x; 28 if(x>9) write(x/10); 29 putchar(x%10+'0'); 30 } 31 const int maxn=500010; 32 const int N=60; 33 const int inf=0x3f3f3f3f; 34 const int INF=0x7fffffff; 35 typedef long long ll; 36 struct node{ 37 int v,net; 38 }e[maxn<<1]; 39 int head[maxn],depth[maxn],lg[maxn],f[maxn][50],cnt; 40 void add(int u,int v) { 41 e[++cnt].v=v; 42 e[cnt].net=head[u]; 43 head[u]=cnt; 44 } 45 void dfs(int fath,int now) { 46 depth[now]=depth[fath]+1; 47 f[now][0]=fath; 48 for(int i=1;(1<<i)<=depth[now];i++) 49 f[now][i]=f[f[now][i-1]][i-1]; 50 for(int i=head[now];i!=-1;i=e[i].net) 51 if(e[i].v!=fath) dfs(now,e[i].v); 52 } 53 int lca(int x,int y) { 54 if(depth[x]<depth[y]) swap(x,y); 55 while(depth[x]>depth[y]) x=f[x][lg[depth[x]-depth[y]]-1];///x往父节点开始延伸 56 if(x==y) return x; ///说明公共祖先为y,也就是当前的x 57 for(int i=lg[depth[x]]-1;~i;i--) 58 if(f[x][i]!=f[y][i]) 59 x=f[x][i],y=f[y][i]; 60 return f[x][0]; 61 } 62 int main() 63 { 64 int n,m,s,a,b; 65 read(n),read(m),read(s); 66 fill(head+1,head+n+1,-1); 67 for(int i=1;i<=n-1;i++) { 68 read(a),read(b); 69 add(a,b),add(b,a); 70 } 71 dfs(s,s); 72 for(int i=1;i<=n;i++) ///常数优化,预处理求出log2[i]+1的值 73 lg[i]=lg[i-1]+(1<<lg[i-1]==i); 74 for(int i=1;i<=m;i++) { 75 read(a),read(b); 76 write(lca(a,b));pn; 77 } 78 return 0; 79 }
所谓人生,一半惊喜,一半遗憾