11 条题解
-
1
#include<bits/stdc++.h> using namespace std; const int MAXN=500000+5; const int MAXM=1000000+5; int head[MAXN];//链式前向星 int father[MAXN];//父亲节点 bool visited[MAXN]; int bianshu; struct edge//链式前向星 { int v,next; }g[2*MAXM];//双向边,记得开2倍范围 void addedge(int u,int v)//链式前向星无权值加边 { g[++bianshu].next=head[u]; g[bianshu].v=v; head[u]=bianshu; return; } queue <int> q;//bfs用 int dep[MAXN];//每个点的深度 void bfs(int s,int depth)//求father { q.push(s); dep[s]=depth; while(!q.empty()) { int ppp=q.front(); q.pop(); for(int i=head[ppp];i;i=g[i].next)//遍历 { if(!visited[g[i].v]) { visited[g[i].v]=true; father[g[i].v]=ppp; dep[g[i].v]=dep[ppp]+1;//存储深度,比父亲节点深度大1 q.push(g[i].v); } } } } int jump[MAXN][35];//定义:j[a][b]为a号点往根节点方向走(1<<b)次后的节点编号 int main() { int n,q,s; int uu,vv; int a,b; int tmp;//深度差 scanf("%d%d",&n,&q);//有时候需要读入s s=1; for(int i=1;i<=n-1;++i) { scanf("%d%d",&uu,&vv); addedge(uu,vv); addedge(vv,uu); }//加边 father[s]=0;//注意:father[根]一定要设为0,否则后面跳跃时出问题 visited[s]=true; bfs(s,1);//求father数组 for(int i=1;i<=n;++i) { jump[i][0]=father[i]; }//jump初值 for(int j=1;j<=30;++j) { for(int i=1;i<=n;++i) { jump[i][j]=jump[jump[i][j-1]][j-1]; } }//初始化jump数组 while(q--)//操作 { scanf("%d%d",&a,&b); tmp=(dep[a]>dep[b]?dep[a]-dep[b]:dep[b]-dep[a]);//深度差值 if(dep[a]>dep[b]) //每次判断是否跳跃(1<<k)次,跳跃到同一深度 { for(int k=30;k>=0;--k) { if(tmp>=(1<<k)) { a=jump[a][k]; tmp-=(1<<k); } } } else if(dep[b]>dep[a]) { for(int k=30;k>=0;--k) { if(tmp>=(1<<k)) { b=jump[b][k]; tmp-=(1<<k); } } }//使得a,b位于同一深度 if(a==b)//跳到同一个点,即LCA就是当前的点,需要特判。 { printf("%d\n",a); continue; } for(int k=30;k>=0;--k) { if((jump[a][k]^jump[b][k]))//异或符号^在此处等价于!= 符号 { a=jump[a][k]; b=jump[b][k]; } }//跳2的k次方次 printf("%d\n",father[a]); } return 0; }
信息
- ID
- 121
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 6
- 标签
- 递交数
- 692
- 已通过
- 202
- 上传者