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

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;
}

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

时间: 2024-11-23 03:43:38

寒假集训第六天---LCA题解的相关文章

POJ 1330 Nearest Common Ancestors LCA题解

本题是一个多叉树,然后求两点的最近公共单亲节点. 就是典型的LCA问题.这是一个很多解法的,而且被研究的很透彻的问题. 原始的解法:从根节点往下搜索,若果搜索到两个节点分别在一个节点的两边,那么这个点就是最近公共单亲节点了. Trajan离线算法:首次找到两个节点的时候,如果记录了他们的最低单亲节点,那么答案就是这个最低的单亲节点了. 问题是如何有效记录这个最低单亲节点,并有效根据遍历的情况更新,这就是利用Union Find(并查集)记录已经找到的节点,并及时更新最新访问的节点的当前最低单亲节

POJ 1470 Closest Common Ancestors LCA题解

本题也是找LCA的题目,不过要求多次查询,一般的暴力查询就必然超时了,故此必须使用更高级的方法,这里使用Tarjan算法. 本题处理Tarjan算法,似乎输入处理也挺麻烦的. 注意: 因为查询的数据会极大,故此使用一个数组记录所有查询数据就会超时的.我就载在这里了.查了好久才想到这点.因为我使用了一个vector容器记录了查询数据,故此每次都循环这组这么大的数据,就超时了.----解决办法:使用一个vector<int> quest来记录查询数组,这样每次都只需要循环某节点的邻接查询点就可以了

CSU-ACM寒假集训选拔-入门题

CSU-ACM寒假集训选拔-入门题 仅选择部分有价值的题 J(2165): 时间旅行 Description 假设 Bobo 位于时间轴(数轴)上 t0 点,他要使用时间机器回到区间 (0,?h] 中. 当 Bobo 位于时间轴上 t 点,同时时间机器有 c 单位燃料时,他可以选择一个满足 \(\lceil\frac{x}{h}\rceil\leq c\) 的非负整数 x, 那么时间机器会在 [0,?x]中随机整数 y,使 Bobo 回到 (t???y) 点,同时消耗 y 单位燃料. (其中 ?

集训第六天:文件上传漏洞

韩舒学姐(相当温柔)今天给我们讲解了文件上传漏洞,以及Anrwsord和Cknife等工具的使用. 文件上传漏洞 上传的文件不进行限制,有可能会被利用于上传可执行文件.脚本到服务器上,并且通过脚本文件可以获得执行服务器端命令的能力 木马 根据语言分类,有PHP.ASP.JSP.ASP.NET等不同语言下的木马:根据作用分类,有大马和小马 PHP一句话木马: <?php ehco shell_exec($_GET['a']); ?> <?php ehco shell_exec($_POST

洛谷2018寒假集训tg第二次比赛第二题Princess Principal题解

这算不算泄题啊...被kkk发现会咕咕咕吧. 题目大意:给定一个数列a,与常数n,m,k然后有m个询问,每个询问给定l,r.问在a[l]到a[r]中最少分成几段,使每段的和不超过k,如果无解,输出Chtholly 样例: input: 5 5 72 3 2 3 43 34 45 51 52 4 output: 11122 解答: 首先观察数据范围,n<=1e+6 可能的复杂度为O(mlogn).暴力能搞30分吧. 其实这题还是很妙的.我们先考虑暴力:对于[L,R],设个res,对[l,r]从左往

集训队寒假集训第二场补题题解

补题什么的待填坑... A - Generous Kefa (语法基础) 直接开桶看看有没有超过三个的,因为题目明确提出没有气球也是可以的 代码 #include <bits/stdc++.h> using namespace std; int bk[123213]; int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n,k; cin>>n>>k; string a; cin>&g

寒假集训第二天---最小生成树题解

CodeForces - 606D Lazy Student 传送门 题目大意:m条边,每条边给权值和是否在最小生成树里,问能否构造出一个图满足边 思路:排序,对可行的边与1相连,对于不可行的边其它已连结点相连,直到连完或者不满足条件 卡点:对于权值相同的边,在最小生成树里的边的优先级较高 代?? #include <iostream> #include <cstdio> #include <algorithm> #include <vector> usin

寒假集训总结

这个寒假的集训吧,缺少了总结. 首先去了秦皇岛的几天还是挺不错的,但是人还是很懒散,没有每日做总结,导致以前会做的题目不会做.COME OJ上的视频也没有看完.秦皇岛开阔了眼界吧. 放寒假前的几天吧,都在聊天,唉,真的有时候会感到孤独... 只写了两场CF的所有题题解对的.(还缺178场) 之后回学校吧一个人在寝室就看看游戏直播的视频,嗯,挺荒废的. 寒假的收货吧,会了时间线段树,一些些STL,dp做了总结,分块+暴力的方法. 之后应该干什么呢,3月17校赛,3月底天梯,4月初浙大校赛,4月底浙

Code[VS] 2370 LCA 题解

Code[VS] 2370 小机房的树 题解 LCA 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力.已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计一个程序来找到这条路,要求你告诉他们最少需要花费多少精力 输入描述 I