LCA——RMQ(线段树)
再学LCA,本来想学RMQ,结果只学会一半,另一半我用线段树写的。
首先,讲一下欧拉序,就是给一个树,从根节点开始,搜索到这个节点时,先在这个时候在序列中记录一下这个节点,然后依次搜索它的子节点,然后当从一个子节点回溯回来时,再在序列中记录一下这个节点,最后当这棵树都被搜索完后,所得到的序列就是这棵树的欧拉序。
然后就说一下这个运用线段树的RMQ的思路:
1.按上面的方式,求出这棵树的欧拉序,并记录每个节点在这个序列中的位置(每个节点只统计一个位置就行)。
2.用dfs求出每个节点的深度。
(上面的两个操作可以同时进行)
3.两个节点的最近公共祖先就是它们所在的最小子树的根节点,这个根节点也是这棵子树中深度最浅的节点,而最小子树的根节点在序列(欧拉序)中的初位置和末位置的中间部分就一定是这棵子树的节点,而这两个节点在序列的位置的中间部分也一定是这课子树上的节点,并且一定有这棵子树的根节点,现在把这个序列看做一棵线段树,两个节点的中间位置看做一个区间,在这个区间中查询这个根节点,即查询这个区间中深度最浅的节点。写一个线段树就可以了。
下面是代码:
#include<iostream> #define MAXN 500001 using namespace std; int read(){ int x=0,f=1; char a=getchar(); while(a<'0'||a>'9'){ if(a=='-')f=-1; a=getchar(); } while(a>='0'&&a<='9'){ x*=10; x+=a-'0'; a=getchar(); } return x*f; } int n,m,s; int head[500010],tot; int a[1000010],cnt; int h[500010],vis[500010]; int dian[500010]; struct node{ int to; int nxt; }edge[1000010]; struct nod{ int l,r; int minn; int jie; }tree[2000010]; void buildbiao(int u,int v){ edge[++tot].to=v; edge[tot].nxt=head[u]; head[u]=tot; } void dfs(int u){ a[++cnt]=u; dian[u]=cnt; for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; if(vis[v]==0){ vis[v]=1; h[v]=h[u]+1; dfs(v); a[++cnt]=u; } } } void build(int i,int l,int r){ tree[i].l=l; tree[i].r=r; if(l==r){ tree[i].minn=h[a[l]]; tree[i].jie=a[l]; return ; } int mid=(l+r)/2; build(i*2,l,mid); build(i*2+1,mid+1,r); if(tree[i*2].minn<tree[i*2+1].minn){ tree[i].minn=tree[i*2].minn; tree[i].jie=tree[i*2].jie; } else{ tree[i].minn=tree[i*2+1].minn; tree[i].jie=tree[i*2+1].jie; } } nod search(int i,int l,int r){ if(tree[i].l>=l&&tree[i].r<=r){ return tree[i]; } nod s1,s2; s1.minn=MAXN; s2.minn=MAXN; if(tree[i*2].r>=l){ s1=search(i*2,l,r); } if(tree[i*2+1].l<=r){ s2=search(i*2+1,l,r); } if(s1.minn>=s2.minn){ s1=s2; } return s1; } int main(){ n=read();m=read();s=read(); for(int i=1;i<n;i++){ int u,v; u=read();v=read(); buildbiao(u,v); buildbiao(v,u); } vis[s]=1; h[s]=1; dfs(s); build(1,1,2*n-2); for(int i=1;i<=m;i++){ int u,v; u=read();v=read(); printf("%d\n",search(1,min(dian[u],dian[v]),max(dian[u],dian[v])).jie); } return 0; }