lca(洛谷P3379 最近公共祖先(LCA))
来源:互联网 发布:阿里大数据查询 编辑:程序博客网 时间:2024/05/29 17:00
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先.
输入格式:
第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。
接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。
接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。
输出格式:
输出包含M行,每行包含一个正整数,依次为每一个询问的结果.
输入样例#1:
5 5 43 12 45 11 42 43 23 51 24 5
输出样例#1:
44144思路的话可以见我的转载博文:传送门
tarjan方法
这是我的代码实现~
%:pragma GCC optmize(3)//o3优化,尽量不要开 #include<bits/stdc++.h>#define maxn 1100010#define maxm 1100130using namespace std;int n,m,ss;struct aaa{int to,next;}edge[maxn];struct bbb{int same,to,next,num;bool flag;bbb(){flag=0;}}s[maxm];int head[maxn],shead[maxm],pre[maxn],book[maxn],ans[maxm];int cnt=0;inline int read()//注意快读 {char c=getchar();int num=0;while(!isdigit(c)) c=getchar();while(isdigit(c)){num=num*10+c-'0';c=getchar();} return num;} void add_edge(int u,int v){edge[++cnt].to=v;edge[cnt].next=head[u];head[u]=cnt;edge[++cnt].to=u;edge[cnt].next=head[v];head[v]=cnt;}int cntt=0;void add_search(int u,int v,int w){s[++cntt].to=v;s[cntt].next=shead[u];s[cntt].num=w;shead[u]=cntt;s[++cntt].to=u;s[cntt].num=w;s[cntt].next=shead[v];shead[v]=cntt;}int find(int x){if(pre[x]==x) return x;else return pre[x]=find(pre[x]);}int merge(int x,int y)//注意谁和谁合并 {int fx=find(x),fy=find(y);if(pre[fy]!=fx){pre[fy]=fx;return 1;}return 0;}void tarjan(int point,int f){for(int i=head[point];i;i=edge[i].next)if(edge[i].to!=f&&!book[edge[i].to])//不能返回之前走过的点——父节点 {tarjan(edge[i].to,point);merge(point,edge[i].to);book[edge[i].to]=1;}for(int i=shead[point];i;i=s[i].next)if(book[s[i].to]&&!s[i].flag){ans[s[i].num]=find(s[i].to);s[i].flag=1;//走过的点标记 int tt=i;if(tt%2)tt++;else tt--;s[tt].flag=1;//因为是双向储存所以两边都要去掉 }}int main(){scanf("%d%d%d",&n,&m,&ss);for(int i=1;i<n;i++){int t1,t2;t1=read();t2=read();add_edge(t1,t2);}for(int i=1;i<=n;i++)pre[i]=i;for(int i=1;i<=m;i++){int t1,t2;t1=read();t2=read();add_search(t1,t2,i);}tarjan(ss,0);//虚构一个父节点 for(int i=1;i<=m;i++)printf("%d\n",ans[i]);return 0;}
倍增的思想
真是巧妙,巧妙的我晕晕转~
这是我的代码~以前的代码风格不是特别好,于是又写了一遍
#include<bits/stdc++.h>#define maxn 600000using namespace std;int n,m,s,cnt=0;int book[maxn],p[maxn][25],deep[maxn],head[maxn];struct Edge{int to,next;}e[maxn*4];void add(int u,int v){e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;}void dfs(int x,int fa){book[x]=1;for(int i=head[x];i;i=e[i].next)if(!book[e[i].to]){deep[e[i].to]=deep[x]+1;p[e[i].to][0]=x;dfs(e[i].to,x);}}void init(){for(int j=1;(1<<j)<=n;j++)for(int i=1;i<=n;i++)p[i][j]=p[p[i][j-1]][j-1];}int lca(int a,int b){if(deep[a]<deep[b]) swap(a,b);//注意是深度 int i=0;int depth=deep[a]-deep[b];while((1<<i)<=n) i++;i--;for(int j=i;j>=0;j--)if((1<<j)&depth) //同样注意是depth寻找二进制位上的1 a=p[a][j];if(a==b) return a;for(int j=i;j>=0;j--){if(p[a][j]!=p[b][j]){a=p[a][j];b=p[b][j];}}return p[a][0];}int main(){scanf("%d%d%d",&n,&m,&s);for(int i=1;i<n;i++){int t1,t2;scanf("%d%d",&t1,&t2);add(t1,t2);add(t2,t1);}deep[s]=0;//这里的深度无论初始化多少都无所谓的 dfs(s,0);init();for(int i=1;i<=m;i++){int t1,t2;scanf("%d%d",&t1,&t2);printf("%d\n",lca(t1,t2)); }return 0;}
阅读全文
0 0
- lca(洛谷P3379 最近公共祖先(LCA))
- P3379 【模板】最近公共祖先(LCA)
- 洛谷 P3379 【模板】最近公共祖先(LCA)
- 洛谷P3379 【模板】最近公共祖先(LCA)
- 洛谷 P3379 【模板】最近公共祖先(LCA)
- 洛谷 P3379 【模板】最近公共祖先(LCA)
- LCA----【模板】最近公共祖先(LCA)
- LCA(最近公共祖先)
- 【最近公共祖先(LCA)】
- 最近公共祖先(LCA)
- 最近公共祖先(LCA)
- LCA(最近公共祖先)
- 最近公共祖先(LCA) 洛谷 3379 LCA
- 最近公共祖先算法(LCA)
- 最近公共祖先算法(LCA)
- 二叉树-最近公共祖先(LCA)
- 最近公共祖先问题(LCA)
- hdu2586(LCA最近公共祖先)
- 求最大子矩阵悬线法(codevs 1159 最大全0子矩阵)
- JS学习第四天
- java操作Redis数据库的redis工具,RedisUtil,jedis工具JedisUtil,JedisPoolUtil
- 悬线法求最大子矩阵(洛谷P1169 [ZJOI2007]棋盘制作 bzoj1057)
- dfs(洛谷1019 单词接龙NOIp2000提高组第三题)
- lca(洛谷P3379 最近公共祖先(LCA))
- poj 2251 Dungeon Master(多起点bfs)
- LCA 最近公共祖先
- 树形dp(人品问题NOIP17提高模拟训练3)
- 使用SSH框架进行开发的时候,由于延迟加载引起的no Session错误解决方法
- 立体井字棋NOIP17提高模拟训练5
- 所有的M数NOIP17提高模拟训练5
- 前端初学学习进程II
- 树形dp(数字转换NOIP17提高模拟训练4)