zoukankan      html  css  js  c++  java
  • hdu2586 LCA

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

    思路:在求解最近公共祖先的问题上,用到的是Tarjan的思想,从根结点开始形成一棵深搜树,非常好的处理技巧就是在回溯到结点u的时候,u的子树已经遍历, 这时候才把u结点放入合并集合中,这样u结点和所有u的子树中的结点的最近公共祖先就是u了,u和还未遍历的所有u的兄弟结点及子树中的最近公共祖先就是 u的父亲结点。以此类推。这样我们在对树深度遍历的时候就很自然的将树中的结点分成若干的集合,两个集合中的所属不同集合的任意一对顶点的公共祖先都是 相同的,也就是说这两个集合的最近公共最先只有一个。对于每个集合而言可以用并查集来优化,时间复杂度就大大降低了,为O(n + q),n为总结点数,q为询问结点对数。

    一般步骤:

    //parent为并查集,FIND为并查集的查找操作
    //QUERY为询问结点对集合
    //TREE为基图有根树
    Tarjan(u)
    visit[u] =true
    for each (u, v) in QUERY
    if visit[v]
    ans(u, v) = FIND(v)
    for each (u, v) in TREE
    if!visit[v]
    Tarjan(v)
    parent[v] = u

    对于本道题的做法就是用dist数组记录任意节点到根节点的距离,然后最终的答案就是dist[u,v]=dist[u]+dist[v]-2*dist[LCA(u,v)]。


     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<vector>
     6 using namespace std;
     7 #define MAXN 44444
     8 
     9 struct Edge{
    10     int v,w,next;
    11 }edge[MAXN*2];
    12 
    13 struct Node{
    14     int v,id;
    15     Node(int _v,int _id):v(_v),id(_id){}
    16 };
    17 
    18 int n,m,NE;
    19 int head[MAXN];
    20 int dist[MAXN];
    21 bool mark[MAXN];
    22 int parent[MAXN];
    23 
    24 void Insert(int u,int v,int w)
    25 {
    26     edge[NE].v=v;
    27     edge[NE].w=w;
    28     edge[NE].next=head[u];
    29     head[u]=NE++;
    30 }
    31 
    32 int Find(int x){
    33     if(x==parent[x]){
    34         return  parent[x];
    35     }
    36     parent[x]=Find(parent[x]);
    37     return parent[x];
    38 }
    39 
    40 int num[MAXN][3];
    41 vector<vector<Node> >map;
    42 void Tarjan(int u)
    43 {
    44     mark[u]=true;
    45     //对于每一个询问
    46     for(int i=0;i<map[u].size();i++){
    47         int v=map[u][i].v,id=map[u][i].id;
    48         if(mark[v])num[id][2]=Find(v);
    49     }
    50     //对于树上的每一个节点
    51     for(int i=head[u];i!=-1;i=edge[i].next){
    52         int v=edge[i].v,w=edge[i].w;
    53         if(!mark[v]){
    54             dist[v]=dist[u]+w;
    55             Tarjan(v);
    56             parent[v]=u;
    57         }
    58     }
    59 }
    60     
    61         
    62             
    63 int main()
    64 {
    65     int _case,u,v,w;
    66     scanf("%d",&_case);
    67     while(_case--){
    68         scanf("%d%d",&n,&m);
    69         NE=0;
    70         memset(head,-1,sizeof(head));
    71         for(int i=1;i<n;i++){
    72             scanf("%d%d%d",&u,&v,&w);
    73             Insert(u,v,w);
    74             Insert(v,u,w);
    75         }
    76         map.clear();
    77         map.resize(n+4);
    78         for(int i=1;i<=m;i++){
    79             scanf("%d%d",&u,&v);
    80             num[i][0]=u;
    81             num[i][1]=v;
    82             map[u].push_back(Node(v,i));
    83             map[v].push_back(Node(u,i));
    84         }
    85         for(int i=1;i<=n;i++)parent[i]=i;
    86         memset(mark,false,sizeof(mark));
    87         dist[1]=0;
    88         Tarjan(1);
    89         for(int i=1;i<=m;i++){
    90             printf("%d
    ",dist[num[i][0]]+dist[num[i][1]]-2*dist[num[i][2]]);
    91         }
    92     }
    93     return 0;
    94 }
    代码君
  • 相关阅读:
    20165331 第五周学习总结
    第二次测试补做
    20165331 《Java程序设计》第四周学习总结
    2018-2019-1 20165237 《信息安全系统设计基础》第二周学习总结
    2018-2019-1 20165237 《信息安全系统设计基础》第一周学习总结
    20165237 2017-2018-2《Java程序设计》课程总结
    2017-2018-2 20165237 实验五《网络编程与安全》实验报告
    2017-2018-2 20165237 实验四《Android开发基础》实验报告
    20165237 2017-2018-2 《Java程序设计》第十周考试补做及编程题
    2017-2018-2 20165237 实验三《 敏捷开发与XP实践》实验报告
  • 原文地址:https://www.cnblogs.com/usedrosee/p/4164027.html
Copyright © 2011-2022 走看看