51Nod 1443 路径和树

还是一道很简单的基础题,就是一个最短路径树的类型题目

我们首先可以发现这棵树必定满足从1出发到其它点的距离都是原图中的最短路

换句话说,这棵树上的每一条边都是原图从1出发到其它点的最短路上的边

那么直接跑最短路,SPFA,不存在的?我只信DJ,然后记录那些边在最短路上

然后直接跑MST即可。是不是很经典的水题

然后我又莫名拿了Rank1(没办法天生自带小常数

CODE

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
const int N=3e5+5;
struct edge
{
    int from,to,next,v;
}e[N<<1];
struct heap
{
    int num; LL s;
    bool operator < (const heap a) const { return a.s<s; }
};
struct data
{
    int l,r,s;
}a[N];
priority_queue <heap> small;
int head[N],cnt,father[N],n,m,x,y,z,s,tot;
LL dis[N];
bool vis[N];
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-‘0‘,isdigit(ch=tc()));
}
inline void double_add(int x,int y,int z)
{
    e[++cnt].from=x; e[cnt].to=y; e[cnt].next=head[x]; e[cnt].v=z; head[x]=cnt;
    e[++cnt].from=y; e[cnt].to=x; e[cnt].next=head[y]; e[cnt].v=z; head[y]=cnt;
}
inline bool cmp(data a,data b)
{
    return a.s<b.s;
}
inline int getfather(int k)
{
    return father[k]^k?father[k]=getfather(father[k]):k;
}
inline LL MST(void)
{
    register int i; LL ans=0;
    sort(a+1,a+tot+1,cmp);
    for (i=1;i<=n;++i)
    father[i]=i;
    for (i=1;i<=tot;++i)
    {
        int fx=getfather(a[i].l),fy=getfather(a[i].r);
        if (!vis[a[i].r]&&fx!=fy) father[fx]=fy,ans+=a[i].s,vis[a[i].r]=1;
    }
    return ans;
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    int i; read(n); read(m);
    memset(head,-1,sizeof(head)); memset(e,-1,sizeof(e));
    for (i=1;i<=m;++i)
    read(x),read(y),read(z),double_add(x,y,z);
    memset(dis,63,sizeof(dis)); read(s);
    dis[s]=0; small.push((heap){s,0});
    while (!small.empty())
    {
        int now=small.top().num; small.pop();
        if (vis[now]) continue; vis[now]=1;
        for (i=head[now];i!=-1;i=e[i].next)
        if (dis[e[i].to]>dis[now]+1LL*e[i].v)
        {
            dis[e[i].to]=dis[now]+1LL*e[i].v;
            small.push((heap){e[i].to,dis[e[i].to]});
        }
    }
    memset(vis,0,sizeof(vis));
    for (i=1;i<=cnt;++i)
    if (dis[e[i].from]+1LL*e[i].v==dis[e[i].to]) a[++tot]=(data){e[i].from,e[i].to,e[i].v};
    return printf("%lld",MST()),0;
}

原文地址:https://www.cnblogs.com/cjjsb/p/9339187.html

时间: 2024-12-29 23:10:32

51Nod 1443 路径和树的相关文章

51nod 1443 路径和树——最短路生成树

题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1443 不只是做一遍最短路.还要在可以选的边里选最短的才行. 以为是求一遍最短路,然后按边权对边排序,哪条边两边的dis正好吻合,就把该边的边权加到ans里,把两端加到并查集里. 但其实不对.因为忽略了方向.比如如果有多个点同样地可以更新一个点,算的时候可能这多个点都因为那个点而被合到了并查集里,但其实只能有一个被合进去. 其实只要松弛点的时候如果dis[v]==d

51nod 配对(求树的重心)

传送门:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1737 给出一棵n个点的树,将这n个点两两配对,求所有可行的方案中配对两点间的距离的总和最大为多少. Input 一个数n(1<=n<=100,000,n保证为偶数) 接下来n-1行每行三个数x,y,z表示有一条长度为z的边连接x和y(0<=z<=1,000,000,000) Output 一个数表示答案 Input示例 6 1 2 1 1 3 1

[BZOJ 1576] 安全路径 最短路径树 路径压缩

题意 给定一张 n 个点 m 条边的图, 保证对于任意的点 i , 从点 1 到点 i 的最短路唯一. 对于任意的点 i , 询问: 将 1 到 i 的最短路中最后一条边删去之后, 从 1 到 i 的最短路 . n <= 100000, m <= 200000 . 分析 首先跑 Dijsktra , 构建出最短路径树. 接下来考虑每条非树边 E[p] = (u, v, d) 对答案的影响, 它能且仅能影响到点 u, v 之上, LCA(u, v) 之下的点的答案. (包括 u, v, 不包括

51nod 1272 思维/线段树

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1272 1272 最大距离 题目来源: Codility 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 收藏 关注 给出一个长度为N的整数数组A,对于每一个数组元素,如果他后面存在大于等于该元素的数,则这两个数可以组成一对.每个元素和自己也可以组成一对.例如:{5, 3, 6, 3, 4, 2},可以组成11对,如下(数字为下标):

51Nod 1806 wangyurzee的树

1806 wangyurzee的树 链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1806 想法:因为$m \le 17$,所以用容斥统计一下.即限定一些$u_i$的度数为$d_i$,然后变成Prufer统计带标号树的计数. #include< cstdio > #define FILE(F) freopen(F".in","r",stdin),freopen(F&quo

51Nod 1737 配对(树的重心)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1737 题意: 思路: 树的重心. 树的重心就是其所以子树的最大的子树结点数最少,删除这个点后最大连通块的结点数最小,也就说各个连通块尽量平衡. 这道题的话就是先求一个重心,然后求各个点到重心的距离之和. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #inclu

[51nod1443]路径和树

给定一幅无向带权连通图G = (V, E) (这里V是点集,E是边集).从点u开始的最短路径树是这样一幅图G1 = (V, E1),其中E1是E的子集,并且在G1中,u到所有其它点的最短路径与他在G中是一样的. 现在给定一幅无向带权连通图G和一个点u.你的任务是找出从u开始的最短路径树,并且这个树中所有边的权值之和要最小. Input 第一行有两个整数n和m(1 ≤ n ≤ 3*10^5, 0 ≤ m ≤ 3*10^5),表示点和边的数目. 接下来m行,每行包含3个整数 ui, vi, wi ,

51Nod 1272最大距离 (树状数组维护前缀最小值)

题目链接 最大距离 其实主流解法应该是单调栈--我用了树状数组. 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 6 7 const int N = 100010; 8 9 struct node{ 10 int x, y; 11 friend bool operator < (const node &a, c

51nod 1967 路径定向(不错的欧拉回路)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1967 题意: 思路: 出度=入度,这很容易想到欧拉回路,事实上,这道题目也确实是用欧拉回路来做的,之前一直觉得应该用网络流来做,可惜想不出,后来看官方题解说也是可以的,但是复杂度太高. 对于每条边,先假设它为无向边,奇点的个数肯定是偶数个,对于这些奇点,我们可以两两连条边,使它们变成偶点,这样一来就肯定存在欧拉回路了,跑一遍就可以了.新加的边是不会影响结果的. 这道题目