[USACO19JAN]Shortcut题解

本题算法:最短路树
这是个啥玩意呢,就是对于一个图,构造一棵树,使从源点开始的单源最短路径与原图一模一样。怎么做呢,跑一边Dijkstra,然后对于一个点u,枚举它的边,设当前的边为cur_edge,如果dis[u]+cue_edge的长度=dis[cur_edge的终点],那么显然这条边应该珂以是最短路树上的一条边,然后打一个标记表示cur_edge的终点不能再被加边了,题目要求字典序最小,显然u从1到n枚举珂以解决问题。
建好树以后跑一边DFS,我们知道当前节点u上连边的贡献是\((dis[u] - t) \times\)\(u\)为根的子树的牛的个数,找到贡献最大的点更新答案即可。

代码:

#include <cstdio>
#include <queue>
#include <algorithm>
#include <set>
#include <map>
#define ll long long

using namespace std;

ll read(){
    ll x = 0; int zf = 1; char ch = ' ';
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}

struct Edge{
    int from, to, next; ll dis;
} edges[1000001];

int head[300001], edge_num = 0;

ll dis[300001];

inline void addEdge(int u, int v, ll w){
    edges[++edge_num] = (Edge){u, v, head[u], w};
    head[u] = edge_num;
}

set< pair<ll, int> > que;
int n, t, s = 1;

void dijkstra(){
    for (int i = 1; i <= n; ++i)
        dis[i] = (1ll << 62);
    dis[s] = 0; que.insert(make_pair(0, s));
    pair<ll, int> uu; int u, v;
    while (!que.empty()){
        uu = *que.begin(); que.erase(uu);
        u = uu.second;
        for (int c_e = head[u]; c_e; c_e = edges[c_e].next){
            v = edges[c_e].to;
            if (dis[u] + edges[c_e].dis < dis[v]){
                que.erase(make_pair(dis[v], v));
                dis[v] = dis[u] + edges[c_e].dis;
                que.insert(make_pair(dis[v], v));
            }
        }
    }
}

vector<int> vec[100001];
ll ans = 0;
int a[100001];
int vis[100001];

int DFS(int u){
    int v, cnt = 0; vis[u] = 1;
    for (int i = 0; i < vec[u].size(); ++i){
        v = vec[u][i];
        if (!vis[v])
            cnt += DFS(v);
    }
    cnt += a[u];
    ans = max(ans, (dis[u] - t) * cnt);
    return cnt;
}

int v2[100001];

signed main(){
    int m; n = read(), m = read(), t = read();
    for (int i = 1; i <= n; ++i) a[i] = read();
    int u, v; ll w;
    for (int i = 1; i <= m; ++i){
        u = read(), v = read(), w = read();
        addEdge(u, v, w), addEdge(v, u, w);
    }
    dijkstra();
    for(int i = 1; i <= n; ++i)
        for(int c_e = head[i]; c_e; c_e = edges[c_e].next)
            if(dis[edges[c_e].to] == dis[i] + edges[c_e].dis && !v2[edges[c_e].to]){
                v2[edges[c_e].to] = 1;
                vec[i].push_back(edges[c_e].to), vec[edges[c_e].to].push_back(i);
            }
    DFS(1);
    printf("%lld", ans);
    return 0;
}
posted @ 2019-06-17 14:58  LinZhengmin  阅读(322)  评论(0编辑  收藏  举报

Contact with me