UVA11354 Bond

很明显满足这个条件的路径就是最小生成树上链接两个点的那条唯一的路径


但是题目有50000个询问,如果单纯的在MST上DFS求值则每次查询的复杂度都是O(n),最后可能高达50000*50000

如果组成一棵有根树,每个点记录了父节点及与父节点距离,则任意两个点肯定会有一个共同祖先,所求的值就是两个点到共同祖先路径上最大边中的较大者,

我们只要记录每个点的深度,先将深度调到一样大,然后一起向上搜索肯定会搜到那个共同祖先(也一边更新两个最大边),每个查询复杂度就是这条路径的长度了,构优化了

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 50000+10;
const int maxm = 100000+10;
struct Edge
{
    int from, to, len;
    Edge(int from, int to, int len)
    {
        this->from = from;
        this->to = to;
        this->len = len;
    }
    bool operator<(const struct Edge &ans)const
    {
        return len > ans.len;
    }
};
vector > adj[maxn];
int pre[maxn], dis[maxn], depth[maxn];//MST的父节点和与父节点的距离、深度
bool vis[maxn];
int dist[maxn];//到MST集合的距离
int n, m, q;
void Init()
{
    int a, b, c;
    for(int i = 1; i <= n; i++)
        adj[i].clear();
    for(int i = 1; i <= m; i++)
    {
        scanf("%d%d%d", &a, &b, &c);
        adj[a].push_back(make_pair(b, c));
        adj[b].push_back(make_pair(a, c));
    }
}

void Prim()
{
    priority_queue myQue;
    for(int i = 1; i <= n; i++)
        vis[i] = false, dist[i] = -1;

    pre[1] = -1;
    depth[1] = 0;
    vis[1] = true;//MST根节点

    for(vector >::iterator it = adj[1].begin(); it != adj[1].end(); it++)
    {
        dist[it->first] = it->second;
        myQue.push(Edge(1, it->first, it->second));
    }

    while(!myQue.empty())
    {
        Edge ans = myQue.top();
        myQue.pop();
        int u = ans.to;
        if(vis[u])
            continue;
        pre[u] = ans.from;
        depth[u] = depth[ans.from]+1;
        vis[u] = true;
        dis[u] = ans.len;//到父节点的距离
        for(vector >::iterator it = adj[u].begin(); it != adj[u].end(); it++)
        {
            int v = it->first;
            if(!vis[v] && (dist[v] == -1 || dist[v] > it->second))
            {
                dist[v] = it->second;
                myQue.push(Edge(u, v, dist[v]));
            }
        }
    }
}

int Query(int a, int b)//a的深度<=b的深度
{
    int m1 = -1, m2 = -1;
    while(depth[a] != depth[b])//将深度调到一样
    {
        m2 = max(m2, dis[b]);
        b = pre[b];
    }
    while(a != b)
    {
        m1 = max(m1, dis[a]);
        m2 = max(m2, dis[b]);
        a = pre[a], b = pre[b];
    }
    return max(m1, m2);
}

void Solve()
{
    int a, b;
    scanf("%d", &q);
    for(int i = 1; i <= q; i++)
    {
        scanf("%d%d", &a, &b);
        if(depth[a] > depth[b])
            swap(a, b);
        printf("%d\n", Query(a, b));
    }
}

int main()
{
    int tcase = 0;
    while(scanf("%d%d", &n, &m) != EOF)
    {
        Init();
        if(tcase++ != 0)
            puts("");
        Prim();
        Solve();
    }
    return 0;
}





你可能感兴趣的:(ACM-UVA,bond,UVA11354)