HDU 2586 LCA模板题

题目链接http://acm.hdu.edu.cn/showproblem.php?pid=2586

题目大意:在一个无向树上,求一条链权和。

解题思路

0

|

1

/   \

2      3

设dist[i]为i到根0的链和,求法(Dfs过程中dist[v]=dist[u]+e[i].w)

对于树中任意两点形成的链,可以通过LCA最近公共祖先剖分。

比如2->3,就可以经过LCA点1:  2->1->3

链和=dist[u]+dist[v]-2*dist[LCA[u,v]]

(0-1-2)+(0-1-3)-2*(0-1)=(2-1-3),有点容斥原理的味道。

LCA比较快的是Tarjan离线法,把全部query也做成一个无向树,离线处理。

过程分为两个stage,stage 1对连接树处理,stage 2对query树处理。

两个stage可以颠倒。正写法 倒写法。在Tarjan(u)中,并查集find(v),可以获得LCA。

LCA存储比较头疼,由于LCA是双向共享的。可以建个ancestor数组,索引是查询序号。

也可以直接存在query树的链式前向星中。

本题双向建一个无向树,任意选择一个起点作为root做LCA都可以。

#include "cstdio"
#include "cstring"
#define maxn 40005
#define maxm 205
int head[maxn],qhead[maxn],dist[maxn],tot1,tot2,f[maxn],vis[maxn],ancestor[maxn];
struct Edge
{
    int to,next,w;
}e[maxn*2];
struct Query
{
    int from,to,next,idx;
}q[maxn*2];
void addedge(int u,int v,int w)
{
    e[tot1].to=v;
    e[tot1].w=w;
    e[tot1].next=head[u];
    head[u]=tot1++;
}
void addquery(int u,int v,int idx)
{
    q[tot2].from=u;
    q[tot2].to=v;
    q[tot2].next=qhead[u];
    q[tot2].idx=idx;
    qhead[u]=tot2++;
}
int find(int x) {return x!=f[x]?f[x]=find(f[x]):x;}
void Union(int u,int v)
{
    u=find(u),v=find(v);
    if(u!=v) f[v]=u;
}
void LCA(int u)
{
    vis[u]=true;
    f[u]=u;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to,w=e[i].w;
        if(!vis[v])
        {
            dist[v]=dist[u]+w;
            LCA(v);
            Union(u,v);
        }
    }
    for(int i=qhead[u];i!=-1;i=q[i].next)
    {
        int v=q[i].to;
        if(vis[v]) ancestor[q[i].idx]=find(v);
        //or storage e[i].lca=e[i^1].lca=find(v)
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    int T,n,m,u,v,c;
    scanf("%d",&T);
    while(T--)
    {
        tot1=tot2=0;
        memset(head,-1,sizeof(head));
        memset(qhead,-1,sizeof(qhead));
        memset(vis,0,sizeof(vis));
        dist[1]=0;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n-1;i++)
        {
            scanf("%d%d%d",&u,&v,&c);
            addedge(u,v,c);
            addedge(v,u,c);
        }
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&u,&v);
            addquery(u,v,i);
            addquery(v,u,i);
        }
        LCA(1);
        for(int i=0;i<tot2;i=i+2)
        {
            int u=q[i].from,v=q[i].to,idx=q[i].idx;
            printf("%d\n",dist[u]+dist[v]-2*dist[ancestor[idx]]);
        }
    }
}
时间: 2024-10-10 12:38:01

HDU 2586 LCA模板题的相关文章

hdu 2586 LCA模板题(离线算法)

http://acm.hdu.edu.cn/showproblem.php?pid=2586 Problem Description There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B&quo

HDU 2586 LCA

LCA模板题. DFS记录好,到根结点的距离. #include <bits/stdc++.h> using namespace std; const int maxn = 40000+5; const int logmaxn = 20; struct Edge { int to,w; }; std::vector<Edge> G[maxn]; int f[maxn],dis[maxn],deep[maxn],p[maxn][20],n; struct LCA { int n; i

Saving Princess claire_(hdu 4308 bfs模板题)

http://acm.hdu.edu.cn/showproblem.php?pid=4308 Saving Princess claire_ Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2305    Accepted Submission(s): 822 Problem Description Princess claire_ wa

hdu 1711 KMP模板题

// hdu 1711 KMP模板题 // 贴个KMP模板吧~~~ #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; const int MAX_N = 1000008; const int MAX_M = 10008; int T[MAX_N]; int p[MAX_M]; int f[MAX_M]; int

HDU 2586 LCA离线算法 tarjan算法

LCA tarjan算法模板题 题意:给一个无根树,有q个询问,每个询问两个点,问两点的距离. 用tarjan离线算法算出每个询问的两点的最近公共祖先 ans[i]=dis[x[i]]+dis[y[i]]-2*dis[z[i]]; //  x[i],y[i]分别存储每次询问的两点,z[i]存储这两点的最近公共祖先 #include "stdio.h" #include "string.h" int tot,n,m; int f[40010],x[40010],y[4

HDU 2586 How far away ? 离线lca模板题

How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8712    Accepted Submission(s): 3047 Problem Description There are n houses in the village and some bidirectional roads connecting

HDU2586 How far away ?(LCA模板题)

题目链接:传送门 题意: 给定一棵树,求两个点之间的距离. 分析: LCA 的模板题目 ans = dis[u]+dis[v] - 2*dis[lca(u,v)]; 在线算法:具体讲解 传送门 代码如下: #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 40010; struc

poj1470(LCA模板题)

题目连接:http://poj.org/problem?id=1470 被输入卡到死...... 开始也看到输入格式的问题了,但是我以为查询的两个点的格式就是(u v)这样,其它地方可以无限空格... 为这一直WA啊,以为是算法哪块写挂了,一直找..... 其实哪都可能有一堆空格(其实题目说的也很清楚了-_-||).... 教训.. 还有一点,刚开始以为给出的第一个节点就是祖先,其实题目并没有这么说,看着图理解就误以为了那样了... 1 #include<cstdio> 2 #include&

hdu 2544 hdu 1874 Dijkstra 模板题

hdu 2544  求点1到点n的最短路 Sample Input2 1 //结点数 边数1 2 3 //u v w3 31 2 52 3 53 1 20 0 Sample Output32 1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <algorithm> 5 # include <cmath> 6 # define LL long