LCA(树上倍增 || rmq&lca||)
背景&&描述
给出一棵根节点为1的树,每次询问两点之间的最近公共祖先。
输入格式
第一行一个整数n表示树的节点个数
第二行n-1个数,第i个数表示点(i+1)的父亲是哪个点。保证第i个数<=i。
第三行一个整数m表示询问个数。
接下来m行,每行有俩整数,表示询问的俩点。
输出格式
共m行,对于每次询问输出最近公共祖先的编号。
样例输入
6 1 2 1 2 4 3 3 5 6 4 2 6
样例输出
2 4 1
数据范围与约定
对于100%的数据:
===================
#include<cstdio> #include<algorithm> #include<cstring> const int N=200050; struct node { int to,next; }e[N]; int first[N],dep[N],visit[N]; int fa[N][30]; int cnt=0; void insert(int u,int v) { e[++cnt].to=v;e[cnt].next=first[u];first[u]=cnt; e[++cnt].to=u;e[cnt].next=first[v];first[v]=cnt; } void dfs(int x) { visit[x]=1; for(int i=1;(1<<i)<=dep[x];i++) fa[x][i]=fa[fa[x][i-1]][i-1]; for(int k=first[x];k;k=e[k].next) if(!visit[e[k].to]) { fa[e[k].to][0]=x; dep[e[k].to]=dep[x]+1; dfs(e[k].to); } } int getlca(int x,int y) { if(dep[x]<dep[y]) std::swap(x,y); int t=dep[x]-dep[y]; for(int i=0;(1<<i)<=t;i++) if((1<<i)&t) x=fa[x][i]; for(int i=25;i>=0;i--) if((1<<i)<=dep[x]&&fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; if(x==y) return x; return fa[x][0]; } int main() { int n; scanf("%d",&n); int k; for(int i=2;i<=n;i++) scanf("%d",&k),insert(i,k); dfs(1); int m; scanf("%d",&m); int p,q; for(int i=1;i<=m;i++) scanf("%d %d",&p,&q),printf("%d\n",getlca(p,q)); return 0; }
LCA树上倍增模版
谢谢brain551的教导;
可以去看他的博客,贼好.
-------------------------
这个一道基本上一模一样的题:
给出一棵以1为根的有n个节点的树。
m个询问,每次询问a与b的最近公共祖先。
----------------------
要LCA树上倍增理解的可以去看看:
http://www.cnblogs.com/yyf0309/p/5972701.html
==============
lca&rmq(st表)
自己写了好久,理解不了别人的,只好自己写了一个;
调了好久只能输出dep;
用了struct 才A了;
(12fs 贼菜;)
区别:f[N<<1][27]是个结构体;(xixi大家应当懂用数组的方法,xixi);
dp就是dp啊!!zi是第几个(i);
lca函数 return 的是 zi;
main 函数 printf 的是 dfn[lca(a,b)];
要学会st表&&rmq;(xixi)
调了好久
#include<cstdio> #include<cstring> #include<algorithm> using std::swap; using std::min; const int N=200017; inline int read() { int ans=0,f=1;char t=getchar(); while(t<'0'||t>'9') f=(t=='-'?-1:1),t=getchar(); while(t>='0'&&t<='9') ans=ans*10+t-'0',t=getchar(); return ans*f; } struct edgt { int depth,zi; }line[N]; int dep[N],tar[N],dfn[N],book[N]; struct node { int from,to,next; }e[N]; int first[N]; int cnt=0; void insert(int u,int v) { e[++cnt].to=v;e[cnt].next=first[u];first[u]=cnt; e[++cnt].to=u;e[cnt].next=first[v];first[v]=cnt; } void dfs(int x) { dfn[++cnt]=x,tar[x]=cnt,line[cnt].depth=dep[x],line[cnt].zi=cnt;book[x]=1; for(int i=first[x];i;i=e[i].next) { // printf("\n**** %d %d\n",e[i].to,dep[e[i].to]); if(!book[e[i].to]) { dep[e[i].to]=dep[x]+1; dfs(e[i].to); line[++cnt].depth=dep[x]; line[cnt].zi=cnt; dfn[cnt]=x; } } } struct flagg { int dp,zi; }f[N<<1][27]; int lg[N<<1]; inline int lca(int l,int r) { l=tar[l],r=tar[r]; if(l>r) swap(l,r); // printf("tar : %d %d\n",l,r) ; int t=lg[r-l+1]; // printf("$ $$ $ : %d %d\n",f[l][t],f[r-(1<<t)+1][t]); int x,y; x=f[l][t].dp,y=f[r-(1<<t)+1][t].dp; if(x<=y) return f[l][t].zi; else return f[r-(1<<t)+1][t].zi; // if(line[a].depth<=line[b].depth) return line[a].zi; // else return line[b].zi; // printf("%%%% %d\n",t); // if(ans==f[l][t]) return dfn[l]; // else return dfn[r-(1<<t)+1]; } int main() { int n; n=read(); int p; for(int i=2;i<=n;i++) p=read(),insert(i,p); dep[1]=1; cnt=0; dfs(1); // for(int i=1;i<=n;i++) printf("%d ",dep[i]); // printf("*********\n"); // for(int i=1;i<=cnt;i++) // printf("std:: i : %d zi : %d line : %d tar : %d dfn : %d\n",i,line[i].zi,line[i].depth,tar[i],dfn[i]); lg[1]=0; for(int i=2;i<=cnt;i++) lg[i]=lg[i>>1]+1; for(int i=1;i<=cnt;i++) f[i][0].dp=line[i].depth,f[i][0].zi=i; int x,y; for(int j=1;j<=22;j++) for(int i=1;i<=cnt-( 1<<(j -1) );i++) { x=f[i][j-1].dp,y=f[ i+( 1<< (j-1) )][ j-1 ].dp; if(x<=y) f[i][j].dp=x,f[i][j].zi=f[i][j-1].zi; else f[i][j].dp=y,f[i][j].zi=f[ i+( 1<< (j-1) )][ j-1 ].zi; } int m=read(); int a,b; for(int i=1;i<=m;i++) { a=read(),b=read(); printf("%d\n",dfn[lca(a,b)]); } return 0; }
--------------
还想用tarjian做做(xixi);