「日常训练」Paths and Trees(Codeforces Round 301 Div.2 E)

题意与分析

代码

#include <bits/stdc++.h>
#define MP make_pair
#define PB emplace_back
#define fi first
#define se second
#define ZERO(x) memset((x), 0, sizeof(x))
#define ALL(x) (x).begin(),(x).end()
#define rep(i, a, b) for (repType i = (a); i <= (b); ++i)
#define per(i, a, b) for (repType i = (a); i >= (b); --i)
#define QUICKIO                      ios::sync_with_stdio(false);     cin.tie(0);                      cout.tie(0);
using namespace std;
using ll=long long;
using repType=int;

struct Edge
{
    int u, v;
    ll w;
    Edge() {}
    Edge(int _u, int _v, ll _w): u(_u), v(_v), w(_w) {}
    bool
    operator < (const Edge& rhs) const
    {
        if(w==rhs.w)
            { return (u==rhs.u)?v<rhs.v:u<rhs.u; }
        else { return w<rhs.w; }
    }
};

const int MAXN=300005;
vector<Edge> edges;
vector<int> G[MAXN];

void
add_edge(int u, int v, ll w)
{
    edges.PB(u, v, w);
    G[u].PB(int(edges.size())-1);
}

ll dist[MAXN];
int pre[MAXN]; // pre: last edge

void
dijkstra(int start)
{
    memset(pre, -1, sizeof(pre));
    memset(dist, 0x3f, sizeof(dist));
    using P=pair<ll, int>;
    priority_queue<P, vector<P>, greater<> > pq; // <dist, pnt>: 大根堆
    dist[start]=0;
    pq.push(MP(0, start));
    while(!pq.empty())
    {
        auto now=pq.top(); pq.pop();
        int u=now.se;
        if(dist[u]<now.fi) { continue; }
        rep(i, 0, int(G[u].size())-1)
        {
            int v=edges[G[u][i]].v;
            ll  w=edges[G[u][i]].w;
            if(dist[v]>dist[u]+w)
            {
                dist[v]=dist[u]+w;
                pre[v]=G[u][i];
                pq.push(MP(dist[v], v));
            }
            else if(dist[v]==dist[u]+w && edges[pre[v]].w>edges[G[u][i]].w)
                { pre[v]=G[u][i]; }
        }
    }
}

int
main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    rep(i, 1, m)
    {
        int u, v;
        ll w;
        scanf("%d%d%lld", &u, &v, &w);
        add_edge(u, v, w);
        add_edge(v, u, w);
    }

    int stp; scanf("%d", &stp);
    dijkstra(stp);

    ll ans=0;
    rep(i, 1, n) if(i!=stp) { ans+=edges[pre[i]].w; }
    printf("%lld\n", ans);
    rep(i, 1, n) if(i!=stp) { printf("%d ", pre[i]/2+1); }
    printf("\n");

    return 0;
}

原文地址:https://www.cnblogs.com/samhx/p/cfr303d2e.html

时间: 2024-10-29 03:37:25

「日常训练」Paths and Trees(Codeforces Round 301 Div.2 E)的相关文章

「日常训练」School Marks(Codeforces Round 301 Div.2 B)

题意与分析(CodeForces 540B) 代码 #include <iostream> #include <cstring> #include <algorithm> #include <vector> #define MP make_pair #define PB push_back #define fi first #define se second #define ZERO(x) memset((x), 0, sizeof(x)) #define

「日常训练」Ice Cave(Codeforces Round 301 Div.2 C)

题意与分析(CodeForces 540C) 这题坑惨了我....我和一道经典的bfs题混淆了,这题比那题简单. 那题大概是这样的,一个冰塔,第一次踩某块会碎,第二次踩碎的会掉落.然后求可行解. 但是这题...是冰塔的一层 也就是说,它只是个稍微有点限制的二维迷宫问题. 后面就好理解了,不过需要考虑下这种数据: 1 2 XX 1 1 1 1 这种数据答案是no.解决的方法可以考虑这样:分成两个数组来记录访问状态:vis数组和block数组. 代码 #include <queue> #inclu

「日常训练」Regular Bridge(Codeforces Round 306 Div.2 D)

题意与分析 图论基础+思维题. 代码 #include <bits/stdc++.h> #define MP make_pair #define PB emplace_back #define fi first #define se second #define ZERO(x) memset((x), 0, sizeof(x)) #define ALL(x) (x).begin(),(x).end() #define rep(i, a, b) for (repType i = (a); i &

DFS/BFS Codeforces Round #301 (Div. 2) C. Ice Cave

题目传送门 1 /* 2 题意:告诉起点终点,踩一次, '.'变成'X',再踩一次,冰块破碎,问是否能使终点冰破碎 3 DFS:如题解所说,分三种情况:1. 如果两点重合,只要往外走一步再走回来就行了:2. 若两点相邻, 4 那么要不就是踩一脚就破了或者踩一脚走开再走回来踩一脚破了:3. 普通的搜索看是否能到达, 5 若能还是要讨论终点踩几脚的问题:) 6 DFS 耗时大,险些超时,可以用BFS来做 7 */ 8 #include <cstdio> 9 #include <algorit

贪心 Codeforces Round #301 (Div. 2) A. Combination Lock

题目传送门 1 /* 2 贪心水题:累加到目标数字的距离,两头找取最小值 3 */ 4 #include <cstdio> 5 #include <iostream> 6 #include <algorithm> 7 #include <cstring> 8 using namespace std; 9 10 const int MAXN = 1e3 + 10; 11 const int INF = 0x3f3f3f3f; 12 char s[MAXN],

贪心 Codeforces Round #301 (Div. 2) B. School Marks

题目传送门 1 /* 2 贪心:首先要注意,y是中位数的要求:先把其他的都设置为1,那么最多有(n-1)/2个比y小的,cnt记录比y小的个数 3 num1是输出的1的个数,numy是除此之外的数都为y,此时的numy是最少需要的,这样才可能中位数大于等于y 4 */ 5 #include <cstdio> 6 #include <iostream> 7 #include <algorithm> 8 #include <cstring> 9 using na

Codeforces Round #301 (Div. 2) -- (A,B,C,D)

题目传送:Codeforces Round #301 (Div. 2) A. Combination Lock 水题,求最小移动次数,简单贪心一下即可 AC代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <stack> #i

「日常训练」Bad Luck Island(Codeforces Round 301 Div.2 D)

题意与分析(CodeForces 540D) 代码 #include <iomanip> #include <iostream> #include <cstring> #include <algorithm> #include <vector> #define MP make_pair #define PB push_back #define fi first #define se second #define ZERO(x) memset((x

「日常训练」Woodcutters(Codeforces Round 303 Div.2 C)

这题惨遭被卡..卡了一个小时,太真实了. 题意与分析 (Codeforces 545C) 题意:给定\(n\)棵树,在\(x\)位置,高为\(h\),然后可以左倒右倒,然后倒下去会占据\([x-h,x]\)或者\([x,x+h]\)区间,如果不砍伐,占据\([x,x]\)区域. 问你最多砍多少棵树,砍树的条件是倒下去后占有的区间不能被其他树占据. 分析:在这条题目的条件下,这是一个傻逼贪心题.(然后我读错两次题目,怎么也想不出来贪心策略....) 很简单的策略:能往左倒往左倒,能往右倒往右倒.因