码迷,mamicode.com
首页 > 其他好文 > 详细

寒假集训第六天---LCA题解

时间:2020-01-19 21:59:34      阅读:71      评论:0      收藏:0      [点我收藏+]

标签:const   name   one   view   ack   names   color   hide   tar   

Gym - 100015C City Driving

题意:给你一个n个点的树再加上一条边,求询问的两个点的最短路

题解:去掉形成的环中的一条边,这样就变成了一个普通的求树上最短路,求得A1,然后求u到删掉边的u,v到删掉边的v,再加上删掉边的权值,求得A2,求v到删掉边的u,u到删掉边的v,再加上删掉边的权值w,求得A3,取最小值即可

我用的是在线倍增,为什么不用tarjan和rmq,我和他们不太熟啊

多组输入,vector忘记初始化了,爷哭了

代??

技术图片
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10 ;
int n ;
int f[maxn], dep[maxn], fa[maxn][20], val[maxn][20] ;
bool use[maxn], visit[maxn] ;
struct Edge
{
    int from, to, dist, id ;
    friend bool operator < (const Edge &x, Edge &y)
    {
        return x.dist < y.dist ;
    }
}edge[maxn << 1] ;
vector<int> v[maxn] ;
vector<int> d[maxn] ;
int Find(int x)
{
    return x == f[x] ? f[x] : f[x] = Find(f[x]) ;
}
void kruskal(int n)
{
    for(int i = 1 ; i <= n ; ++ i) f[i] = i ;
    int cnt = 0 ;
    for(int i = 1 ; i <= n ; ++ i)
    {
        int from = edge[i].from, to = edge[i].to ;
        int fx = Find(from), fy = Find(to) ;
        if(fx != fy)
        {
            ++ cnt ;
            use[i] = 1 ;
            f[fx] = fy ;
            v[from].push_back(to) ;
            v[to].push_back(from) ;
            d[from].push_back(edge[i].dist) ;
            d[to].push_back(edge[i].dist) ;
            if(cnt == n - 1) break ;
        }
    }
}
void dfs(int now, int step)
{
    visit[now] = 1 ;
    dep[now] = step ;
    for(int i = 0 ; i < v[now].size() ; ++ i)
    {
        int to = v[now][i] ;
        //printf("%d %d\n",now,to) ;
        if(visit[to] == 0)
        {
            fa[to][0] = now ;
            val[to][0] = d[now][i] ;
            dfs(to,step+1) ;
        }
    }
}
int LCA(int x, int y)
{
    int ans = 0 ;
    if(dep[x] < dep[y]) swap(x,y) ;
    for(int i = 18 ; i >= 0 ; -- i)
    {
        if(dep[fa[x][i]] >= dep[y])
        {
            ans += val[x][i] ;
            x = fa[x][i] ;
        }
    }
    if(x == y) return ans ;
    for(int i = 18 ; i >= 0 ; -- i)
    {
        if(fa[x][i] != fa[y][i])
        {
            ans += val[x][i] + val[y][i] ;
            x = fa[x][i] ;
            y = fa[y][i] ;
        }
    }
    ans += val[x][0] + val[y][0] ;
    return ans ;
}
int main(int argc, char const *argv[])
{
    while(scanf("%d",&n) != EOF )
    {
        if(n == 0) break ;
        memset(use,0,sizeof use) ;
        memset(visit,0,sizeof visit) ;
        memset(val,0,sizeof val) ;
        for(int i = 1 ; i <= n ; ++ i) v[i].clear(), d[i].clear() ;
        for(int i = 1, from, to, dist ; i <= n ; ++ i)
        {
            scanf("%d %d %d",&from,&to,&dist) ;
            edge[i].from = from + 1 ;
            edge[i].to = to + 1 ;
            edge[i].dist = dist ;
            edge[i].id = i ;
        }
        sort(edge+1,edge+1+n) ;
        kruskal(n) ;
        Edge noUse ;
        for(int i = 1 ; i <= n ; ++ i)
        {
            if(use[i] == 0)
            {
                noUse.from = edge[i].from ;
                noUse.to = edge[i].to ;
                noUse.dist = edge[i].dist ;
            }
        }
        fa[1][0] = 0 ;
        dep[0] = -1 ;
        dfs(1,0) ;

        for(int j = 1 ; j <= 18 ; ++ j)
        {
            for(int i = 1 ; i <= n ; ++ i)
            {
                fa[i][j] = fa[fa[i][j-1]][j-1] ;
                val[i][j] = val[i][j-1] + val[fa[i][j-1]][j-1] ;
            }
        }
        int q ;
        scanf("%d",&q) ;
        while(q --)
        {
            int x, y ;
            scanf("%d %d",&x,&y) ;
            x ++ ; y ++ ;
            printf("%d\n",min(LCA(x,y), min(LCA(x,noUse.from) + LCA(y,noUse.to) + noUse.dist, LCA(y,noUse.from) + LCA(x,noUse.to) + noUse.dist ))) ;
        }
    }
    return 0;
}
View Code

寒假集训第六天---LCA题解

标签:const   name   one   view   ack   names   color   hide   tar   

原文地址:https://www.cnblogs.com/wifePI/p/12215593.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!