lca 在线算法 zoj 3195

题目链接:Design the city

题目大意是对给定3点,求这三个点只之间的最短距离。三个点两两组合求lca:dis[u]+dis[v]-dis[lca];将三个组合值相加除以2即为答案。

RMQ算法学习:http://blog.csdn.net/liang5630/article/details/7917702

对于lca->RMQ的转化,可以参看巨巨写的ppt。

欧拉序列:euler[N];

深度序列:depth[N];

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;
const int maxn=50000+10;
const int M=20;
int n,tot,T;
int vis[maxn],euler[maxn<<1],depth[maxn<<1],pos[maxn],bit[M],head[maxn],dis[maxn];
int dp[maxn<<1][M];
struct node
{
    int v,w,next;
}e[maxn<<1];
inline void Swap(int &a,int &b)
{
    int c;
    c=a;
    a=b;
    b=c;
}
void build(int u,int v,int w)
{
    e[T].v=v;
    e[T].w=w;
    e[T].next=head[u];
    head[u]=T++;
}
void init()
{
    memset(vis,0,sizeof(vis));
    memset(head,-1,sizeof(head));
    memset(dis,0,sizeof(dis));
    T=0;
    tot=0;
    int u,v,w;
    for(int i=0;i<n-1;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        build(u,v,w);
        build(v,u,w);
    }
}
void dfs(int u,int dep)
{
    vis[u]=1;
    euler[++tot]=u;
    pos[u]=tot;
    depth[tot]=dep;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].v;
        if(!vis[v])
        {
            int v=e[i].v;
            dis[v]=dis[u]+e[i].w;
            dfs(v,dep+1);
            euler[++tot]=u;
            depth[tot]=dep;
        }

    }
}
void ST(int len)
{
    int k=(int)(log(len*1.0)/log(2.0));
    for(int i=1;i<=len;i++)
        dp[i][0]=i;
    for(int j=1;j<=k;j++)
    {
        for(int i=1;i+bit[j]<=len;i++)
        {
            int l=dp[i][j-1];
            int r=dp[i+bit[j-1]][j-1];
            dp[i][j]=depth[l]<depth[r]?l:r;
        }
    }
}
int RMQ(int x,int y)
{
    int k=(int)(log((y-x+1)*1.0)/log(2.0));
    int l=dp[x][k];
    int r=dp[y-bit[k]+1][k];
    return depth[l]<depth[r]?l:r;
}
int LCA(int u,int v)
{
    int l=pos[u];
    int r=pos[v];
    if(l>r)
        Swap(l,r);
    int res=RMQ(l,r);
    return euler[res];
}
int main()
{
    //freopen("in.txt","r",stdin);
    for(int i=0;i<=M;i++)
        bit[i]=1<<i;
    int kase=0;
    while(~scanf("%d",&n))
    {
        if(kase!=0)
            printf("\n");
        kase++;
        init();
        dfs(0,1);
        ST(2*n-1);
        int q;
        scanf("%d",&q);
        int a,b,c,lca[3],p;
        while(q--)
        {
            scanf("%d%d%d",&a,&b,&c);
            p=LCA(a,b);
            lca[0]=dis[a]+dis[b]-2*dis[p];
            p=LCA(b,c);
            lca[1]=dis[b]+dis[c]-2*dis[p];
            p=LCA(a,c);
            lca[2]=dis[a]+dis[c]-2*dis[p];
            printf("%d\n",(lca[0]+lca[1]+lca[2])/2);
        }
    }
    return 0;
}
时间: 2024-08-28 07:04:36

lca 在线算法 zoj 3195的相关文章

hihocoder1069最近公共祖先&#183;三(LCA在线算法--DFS+RMQ-ST)

树上任意两点的最近祖先,必定就是这两个节点的最短路径上深度最小的那个点. 例如:下图中,节点7和5,其最短路径为7--4--1--5, 这条路径上深度最小的点为节点1,其深度为1.节点1即为节点7和5的LCA. 因此,要找到任意两个节点的LCA,只需要先找到上述最短路径,再找到最短路径中深度最小的点.而这下面所述LCA在线算法所做的事. LCA在线算法描述(以上图为例): 1.获得“最短路径”(并不是真正的一条路径,包含其他节点,但不影响算法的正确性) 采用DFS遍历整棵树,得到以下数据: (1

LCA在线算法ST算法

求LCA(最近公共祖先)的算法有好多,按在线和离线分为在线算法和离线算法. 离线算法有基于搜索的Tarjan算法较优,而在线算法则是基于dp的ST算法较优. 首先说一下ST算法. 这个算法是基于RMQ(区间最大最小值编号)的,不懂的可以这里学习一些 而求LCA就是把树通过深搜得到一个序列,然后转化为求区间的最小编号. 比如说给出这样一棵树. 我们通过深搜可以得到这样一个序列: 节点ver 1 3 1 2 5 7 5 6 5 2 4 2 1 (先右后左) 深度R 1 2 1 2 3 4 3 4 3

LCA在线算法详解

LCA(最近公共祖先)的求法有多种,这里先介绍第一种:在线算法. 声明一下:下面的内容参考了http://www.cnblogs.com/scau20110726/archive/2013/05/26/3100812.html. 在线算法就是利用了DFS和RMQ两种算法,它先是预处理好所有情况,然后根据输入输出答案,在输入比较多的时候用比较好. 上面两张图介绍了在线算法的做法,要理解并不难,下面附上实现代码: 1 /******************************* 2 dfs实现代

HDU 2586 How far away ?(LCA在线算法实现)

http://acm.hdu.edu.cn/showproblem.php?pid=2586 题意:给出一棵树,求出树上任意两点之间的距离. 思路: 这道题可以利用LCA来做,记录好每个点距离根结点的距离,然后只要计算出两点的LCA,这样一来答案就是distance[u]+distance[v]-2distance[LCA]. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #includ

hdu2874 LCA在线算法

Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 8857    Accepted Submission(s): 2151 Problem Description After World War X, a lot of cities have been seriously damag

LCA最近公共祖先 在线算法和离线算法 模板

原理讲解:http://dongxicheng.org/structure/lca-rmq/ 在线算法模板: /** LCA在线算法O(nlogn) 主函数调用: init(); tot=0,dir[1]=0; dfs(1,1); ST(2*n-1); int lca=LCA(u,v); */ #include <stdio.h> #include <string.h> #include <algorithm> #include <iostream> #in

hdu 3078(LCA的在线算法)

Network Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 847    Accepted Submission(s): 347 Problem Description The ALPC company is now working on his own network system, which is connecting all

LCA(倍增在线算法) codevs 2370 小机房的树

codevs 2370 小机房的树 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力.已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计

最近公共祖先(LCA):离线&amp;在线算法

问题:求两个结点的最近公共祖先(即在树中的公共祖先中高度最低的祖先),下面介绍两种适用于不同场景的算法. Hiho15:离线Tarjan算法 基本思想 Tarjan算法适用于离线批量处理多个查询请求.基本思想是以深度优先搜索的顺序访问这颗树,给这棵树的结点染色,一开始所有结点都是白色的,而当第一次经过某个结点的时候,将它染成灰色,而当第二次经过这个结点的时候--也就是离开这棵子树的时候,将它染成黑色. 这样做的意义,举例说明,当我们深度优先搜索到A结点时,我们发现A结点和B结点是我们需要处理的一