zoukankan      html  css  js  c++  java
  • 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
    ",dist[u]+dist[v]-2*dist[ancestor[idx]]);
            }
        }
    }
  • 相关阅读:
    socket学习笔记——获取域名与IP(linux)
    socket学习笔记——实现收发文件(Windows)
    socket学习笔记——IO口的基本操作(读、写)
    Microsoft Visual C++ 2010(86) Redistributable不能安装完美解决
    AD转换精度的计算
    cuda编程基础
    CUDA中并行规约(Parallel Reduction)的优化
    Warp divergence
    提取图片中文字
    GPU基本概念详解
  • 原文地址:https://www.cnblogs.com/neopenx/p/4502053.html
Copyright © 2011-2022 走看看