LCA的两种写法

第一种是离线的Tarjan算法

#include<cstdio>
using namespace std;
int rd(){
    int x=0,fl=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘){fl=-1;}ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return fl*x;
}
int n,m,s,x,y,num1,num2;
int f[500001],dis[500001],a[500001][3],hd1[500001],hd2[500001];
bool vis[500001];
struct star{int nt,to,ds;}e[1000001],e2[1000001];
void add1(int from,int to){
    e[++num1].nt=hd1[from];
    e[num1].to=to;
    hd1[from]=num1;
}
void add2(int from,int to,int ds){
    e2[++num2].nt=hd2[from];
    e2[num2].to=to;
    e2[num2].ds=ds;
    hd2[from]=num2;
}
int find(int x){
    if(f[x]!=x)
        f[x]=find(f[x]);
    return f[x];
}
void un(int x,int y){
    int ra=find(x),rb=find(y);
    f[ra]=rb;
}
void tarjan(int x){
    vis[x]=1;
    for(int i=hd2[x];i;i=e2[i].nt){
        int to=e2[i].to,dis=e2[i].ds;
        if(vis[to])
            a[dis][2]=find(to);
    }
    for(int i=hd1[x];i;i=e[i].nt){
        int to=e[i].to;
        if(!vis[to]){
            tarjan(to);
            un(to,x);
        }
    }
}
int main(){
    n=rd();m=rd();s=rd();
    for(int i=1;i<n;i++){
        x=rd();y=rd();
        add1(x,y);add1(y,x);
    }
    for(int i=1;i<=m;i++){
        x=rd();y=rd();
        a[i][0]=x;a[i][1]=y;
        add2(x,y,i);add2(y,x,i);
    }
    for(int i=1;i<=n;i++)f[i]=i;
    tarjan(s);
    for(int i=1;i<=m;i++)
        printf("%d\n",a[i][2]);
    return 0;
}

这个代码跑的飞快但是不太好理解。。

还有一种用倍增的思想

#include<iostream>
#include<cstdio>
using namespace std;
int rd(){
    int x=0,fl=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘){fl=-1;}ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return fl*x;
}
int n,m,x,y,s,num=0,hd[500100],dep[500100],f[500100][21];
struct star{int nt,to;}e[1000100];
void add(int fm,int to){e[++num].to=to;e[num].nt=hd[fm];hd[fm]=num;}
void dfs(int x,int fa){
    dep[x]=dep[fa]+1;
    for(int i=1;i<=20;i++)
        f[x][i]=f[f[x][i-1]][i-1];
    for(int i=hd[x];i;i=e[i].nt)
    {
        int to=e[i].to;
        if(to==fa)continue;
        f[to][0]=x;
        dfs(to,x);
    }
}
int lca(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    for(int i=20;i>=0;i--){
        if(dep[f[u][i]]>=dep[v])
            u=f[u][i];
        if(u==v)return u;
    }
    for(int i=20;i>=0;i--)
        if(f[u][i]!=f[v][i]){
            u=f[u][i];v=f[v][i];
        }
    return f[u][0];
}
void print(int x){
    if(x<0){putchar(‘-‘);x=-x;}
    if(x>9)print(x/10);
    putchar(x%10+‘0‘);
}
int main(){
    n=rd();m=rd();s=rd();
    for(int i=1;i<n;i++){
        x=rd();y=rd();
        add(x,y);add(y,x);
    }
    dfs(s,0);
    for(int i=1;i<=m;i++){
        x=rd();y=rd();
        print(lca(x,y));
        putchar(‘\n‘);
    }
    return 0;
}

emmm....这种比较好理解但是跑的有点慢...

如果不太懂...可以看这个/**/

其实还有一种bfs版的玄学算法也安利一下

/* */

时间: 2024-10-08 06:05:47

LCA的两种写法的相关文章

for循环的两种写法

教程 (https://tour.golang.org/methods/21) 里的 for 是这样写的: 其中 for 语句可以改写如下: for n, err := r.Read(b); err != io.EOF; n, err = r.Read(b) { fmt.Printf("n = %v err = %v b = %v\n", n, err, b) fmt.Printf("b[:n] = %q\n", b[:n]) } (当然,golang 里的 for

sql sever 的两种写法

事务(Transaction)是并发控制的单位,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位. 通过事务,SQL Server能将逻辑相关的一组操作绑定在一起,以便服务器保持数据的完整性. 在sql server+ .net 开发环境下,有两种方法能够完成事务的操作,保持数据库的数据完整性: 一个就是用sql存储过程,另一个就是在ADO.NET中一种简单的事务处理: 现在通过一个典型的银行转账的例子来说明一下这两个例子的用法 我们先来看看sql存储过程是如何来

angularJs中$q的两种写法

带缓存处理的两种写法 过程:点击button触发load()方法,请求数据成后显示到页面中.如果已经请求过则从缓存中读取. 在线浏览 写法1: function demo(){ if (demo.cache == undefined) { return $http.get('https://api.github.com/users/github') .success(function(data, status, headers){ demo.cache = data; return $q(fun

描述性编程的两种写法

对象库编程(ORP)是一个非常强大的功能,如果对象名字改变了,只需要进入对象库修改对象,脚本即可批量更新. 描述性编程(DP)不需要维护庞大的对象库,而需要维护庞大的代码,但是在某些情况下(比如对象不能添加到对象库)它很有用. 下面通过一个例子来学习如何进行描述性编程: 首先,我们录制一段在百度首页输入“abcde”,然后点击“百度一下”的代码: Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd"

case的两种写法

case 表达式 when case1 then value1,case 2 then value2,...else endcase 1  when 2 then 3 when 1 then 4 else 5 end如果要再这个基础上加条件的话,只能在他外面嵌套一个case了应为这个case的表达式已经锁定 case when 表达式=1 then value1 ,when 表达式=2 then value2 else value end第二种方式是把表达式写在里面.这样写的多这种方式的好处:当

可拖动弹窗的JS和jQuery两种写法

最近在慕课网上学习了一个网页可拖动对话框js实现的演示视频,这个demo中的例子是百度首页登录按钮的弹窗,如下图: 当点击左上角的登录按钮时,弹窗出现并自动居中,同时窗口可拖动的范围被限制在了可视区域内,即浏览器视窗的上下左右边界,弹窗无法移出移动出四个边界,也不会出现滚动条. 另一个效果就是,当改变窗口大小时,对话框自动居中. 这个视频中用了原生js,jQuery两种写法实现案例,但本质上,对话框居中,限制拖动范围的的计算思路是一致的. 为了简化页面,总结核心思路,我重新写了一个小demo,界

ORACLE 查询一个数据表后通过遍历再插入另一个表中的两种写法

ORACLE 查询一个数据表后通过遍历再插入另一个表中的两种写法 语法 第一种: 通过使用Oracle语句块  --指定文档所有部门都能查看 declare cursor TABLE_DEPT is SELECT ID,UNAME from g_users where utype=2 and STATUS>-1; begin for c in TABLE_DEPT loop INSERT INTO G_KNOWDOCRIGHT(RID,DIRID,DOCID,USERID) VALUES(SYS

状态机的两种写法

状态机的两种写法 发布时间: 2015-09-13 13:22  阅读: 1972 次  推荐: 3   [收藏] 有限状态机FSM思想广泛应用于硬件控制电路设计,也是软件上常用的一种处理方法(软件上称为FMM有限消息机).它把复杂的控制逻辑分解成有限个稳定状态,在每个状态上判断事件,变连续处理为离散数字处理,符合计算机的工作特点.同时,因为有限状态机具有有限个状态,所以可以在实际的工程上实现.但这并不意味着其只能进行有限次的处理,相反,有限状态机是闭环系统,有限无穷,可以用有限的状态,处理无穷

sp_executesql 两种写法

写法1: AlTER PROCEDURE TryAgain @ReturnValue int output AS declare @aa nvarchar(1000), @ForumID int, @count int, @TotalRecords int BEGIN set @ForumID =1 set @aa=N'select @ReturnValue=count(1) from TC_BBS_Topics tc_bt where ForumID='+convert(varchar(10)