[笔记]LCA 最近公共祖先---tarjan离线算法

来源:互联网 发布:c语言函数声明与调用 编辑:程序博客网 时间:2024/06/06 09:40

一.定义:(出自百度百科)

对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v的祖先且x的深度尽可能大。

二.离线算法(同上):

在开始时就需要知道问题的所有输入数据,而且在解决一个问题后就要立即输出结果。

即在算法开始前保存好所有的查询,结束后输出过程中求得的ans

三:基本思路
看到dalao的blog,本蒟蒻已无地自容 这是借口

四.伪代码(还是楼上的)

预处理:fa[1]=1; vis[1]=1; //默认1为根

Tarjan(u)//marge和find为并查集合并函数和查找函数{    for each(u,v)    //访问所有u子节点v    if(!vis[v])    {       标记v被访问过:vis[v]=1;       初始化fa[v]=v;         Tarjan(v);        //继续往下遍历         marge(u,v);    //合并v到u上    }    for each(u,e)    //访问所有和u有询问关系的e    {        如果e被访问过;        u,e的最近公共祖先为find(e);    }}

五.查询的储存
  类前向星

struct Query{    int to; //v    int next; //下一个    int index;  //查询编号};int ans[20005]; //记录ansint qcnt; //结构体大小int qhead[10005]; //u的索引Query query[40005]; inline void addQuery(int x,int y,int z) //加入{    ++qcnt;    query[qcnt].to=y;    query[qcnt].next=qhead[x];    query[qcnt].index=z;    qhead[x]=qcnt;}

六.模板

#include <cstdio>#include <cstdlib>#define open(s) freopen(s".in","r",stdin); freopen(s".out","w",stdout);#define close fclose(stdin); fclose(stdout); using namespace std;struct Edge{    int to;    int next;};int ecnt;int head[500005];Edge edge[1000005];inline void addEdge(int x,int y){    ++ecnt;    edge[ecnt].to=y;    edge[ecnt].next=head[x];    head[x]=ecnt;}struct Query{    int to;    int next;    int index;};int ans[500005];int qcnt;int qhead[500005];Query query[1000005];inline void addQuery(int x,int y,int z){    ++qcnt;    query[qcnt].to=y;    query[qcnt].next=qhead[x];    query[qcnt].index=z;    qhead[x]=qcnt;}int vis[500005];int fa[500005];inline int read(){    int k=1;    int sum=0;    char c=getchar();    for(;'0'>c || c>'9' ;c=getchar())        if(c=='-') k=-1;    for(;'0'<=c && c<='9';c=getchar())        sum=sum*10+c-'0';    return sum*k;}inline void write(int x){    if(x<0) { putchar('-'); x*=-1; }    if(x>9) write(x/10);    putchar(x%10+'0');}inline int find(int x){    return fa[x]=(fa[x]==x?x:find(fa[x]));}inline void join(int x,int y){    int x1=find(x),y1=find(y);    if(x1==y1) return ;    fa[y1]=x1;}inline void LCA(int p){    for(int i=head[p];i;i=edge[i].next)    if(!vis[edge[i].to])    {        int y=edge[i].to;        vis[y]=1;        fa[y]=y;        LCA(y);        join(p,y);    }    for(int i=qhead[p];i;i=query[i].next)    if(!ans[query[i].index] && vis[query[i].to])    {        int y=query[i].to,z=query[i].index;        ans[z]=find(y);    }}int main(){    open("3379");    int n=read(),m=read();    int x1=read();    for(int i=1;i<n;++i)    {        int x=read(),y=read();        addEdge(x,y);        addEdge(y,x);    }    for(int i=1;i<=m;++i)    {        int x=read(),y=read();        addQuery(x,y,i);        addQuery(y,x,i);    }    fa[x1]=x1;    vis[x1]=1;    LCA(x1);    for(int i=1;i<=m;++i)    {        write(ans[i]);        putchar('\n');    }    close;    return 0;}
阅读全文
0 0
原创粉丝点击