zoukankan      html  css  js  c++  java
  • TTTTTTTTTTTTTTTTT HDU 2586 How far away LCA的离线算法 Tarjan

    链接:

    How far away ?

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 11204    Accepted Submission(s): 4079


    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"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.
     
    Input
    First line is a single integer T(T<=10), indicating the number of test cases.
      For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
      Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
     
    Output
    For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
     
    Sample Input
    2 3 2 1 2 10 3 1 15 1 2 2 3 2 2 1 2 100 1 2 2 1
     
    Sample Output
    10 25 100 100
     
    一个村子里有n个房子,这n个房子用n-1条路连接起来,接下了有m次询问,每次询问两个房子a,b之间的距离是多少。
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    #include <algorithm>
    #include <set>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long Ull;
    #define MM(a,b) memset(a,b,sizeof(a));
    const double eps = 1e-10;
    const int  inf =0x7f7f7f7f;
    const double pi=acos(-1);
    const int maxn=40000;
    
    struct Edge{
        int to,w;
        Edge(int a,int b):to(a),w(b){};
        Edge(){};
    }e[maxn+10];
    
    struct node{
       int to,id;
    };
    
    vector<Edge> G[maxn+10];
    vector<node> mp[maxn+10];
    int vis[maxn+10],query[maxn+10][4],par[maxn+10],dis[maxn+10];
    
    int findr(int u)
    {
        if(par[u]!=u)
            par[u]=findr(par[u]);
        return par[u];
    }
    
    void unite(int u,int v)
    {
        int ru=findr(u);
        int rv=findr(v);
        if(ru!=rv) par[rv]=ru;
    }
    
    void tarjan(int u,int val)
    {
        vis[u]=1;
        dis[u]=val;
    
        for(int i=0;i<mp[u].size();i++)
        {
            int v=mp[u][i].to;
            int id=mp[u][i].id;
            if(vis[v])
                query[id][2]=findr(v);
        }
    
        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i].to;
            if(vis[v]) continue;
            tarjan(v,val+G[u][i].w);
            unite(u,v);
        }
    
    }
    
    int main()
    {
        int cas,n,op,u,v,w;
        scanf("%d",&cas);
        while(cas--)
        {
            scanf("%d %d",&n,&op);
    
            for(int i=1;i<=n;i++)
            {
                G[i].clear();
                mp[i].clear();
                vis[i]=0;
                par[i]=i;
            }
    
            for(int i=1;i<=n-1;i++)
            {
                scanf("%d %d %d",&u,&v,&w);
                G[u].push_back(Edge(v,w));
                G[v].push_back(Edge(u,w));
            }
    
            for(int i=1;i<=op;i++)
            {
                scanf("%d %d",&u,&v);
                query[i][0]=u;
                query[i][1]=v;
                mp[u].push_back((node){v,i});
                mp[v].push_back((node){u,i});
            }
    
            tarjan(1,0);
    
            for(int i=1;i<=op;i++)
            {
                int u=query[i][0];
                int v=query[i][1];
                int r=query[i][2];
                printf("%d
    ",dis[u]+dis[v]-2*dis[r]);
            }
        }
        return 0;
    }

    分析:用的lca

    1.因为有n-1条边,任意两点之间可达,那么就是一棵树;

    2,假设当前是询问u和v两个点,他们的LCA是r,dis[]数组代表从根到点的距离,那么u和v两点之间的距离就是dis[u]+dis[v]-2*dis[r];所以只需要用Tarjan求一求询问的点对的LCA并且记录一下每个点到根(随便哪个点做根都可以)的距离就可以了

  • 相关阅读:
    混合背包
    二维背包
    0/1背包问题(DP)
    冒泡排序
    快速排序
    最长上升子序列
    二分查找
    n后问题
    crontab 定时任务
    删除以某字符串开头的表
  • 原文地址:https://www.cnblogs.com/smilesundream/p/5455020.html
Copyright © 2011-2022 走看看