[Atcoder ABC222] F - Expensive Expense | 妙用树的直径 | Dijkstra

简介: Problem StatementThe Kingdom of AtCoder is composed of N towns and N−1 roads.The towns are labeled as Town 1, Town 2, …, Town N. Similarly, the roads are labeled as Road 1, Road 2, …, Road N−1. Road i connects Towns Ai and Bi bidirectionally, and you have to pay the toll of Ci to go through it.

Time Limit: 4 sec / Memory Limit: 1024 MB

Score : 500 points


Problem Statement


The Kingdom of AtCoder is composed of N towns and N−1 roads.

The towns are labeled as Town 1, Town 2, …, Town N. Similarly, the roads are labeled as Road 1, Road 2, …, Road N−1. Road i connects Towns Ai and Bi  bidirectionally, and you have to pay the toll of Ci to go through it. For every pair of different towns ( i , j ) , it is possible to go from Town Ai to Town Bj via the roads.

You are given a sequence D = ( D 1 , D 2 , … , D N )where Di is the cost to do sightseeing in Town i. Let us define the travel cost Ei ,jfrom Town i to Town j as the total toll incurred when going from Town i to Town j , plus Dj . More formally, Ei,j

 is defined as  , where the shortest path between i and j is i = p 0 , p 1 , … , p k − 1 , p k = jand the toll for the road connecting Towns p l  and p l + 1 is c l .


For every i, find the maximum possible travel cost when traveling from Town i to another town.

1e05cabece214c97a16048ea24ab6b49.png

6c4d5d12309b474bbdba08255f231682.png

2818b4ddf66d4a77861895b7985f9a6b.png


Sample Input 1


Copy

3
1 2 2
2 3 3
1 2 3


Sample Output 1


Copy

8
6
6

cd1f9ab095484c2f911698fd6b50800f.png


Sample Input 2


Copy

6
1 2 3
1 3 1
1 4 4
1 5 1
1 6 5
9 2 6 5 3 100


Sample Output 2


Copy

105
108
106
109
106
14


Sample Input 3


Copy

6
1 2 1000000000
2 3 1000000000
3 4 1000000000
4 5 1000000000
5 6 1000000000
1 2 3 4 5 6


Sample Output 3


Copy

5000000006
4000000006
3000000006
3000000001
4000000001
5000000001

不得不说题解给的很妙


树的直径


换根dp

树的直径:


树中任意两点之间的最短距离的最大值,即为树的直径,树的直径是树上两点之间的距离的最大值,对于题目中给定的代表节点游览花费D数组,对于某一个节点u的值  D[u]我们可以当最是有另外的一个节点 u' 与u连了一条值为 D[u],然后在找直径的时候顺便把D 考虑进去,然后找到树的直径的两个端点之后,在进行两次最短路,分别将得到的距离dis[]存放起来


下面在算贡献的时候,直接找该点到端点(记得是两个)的距离的最大值即可


方法1:


#define Clear(x, val) memset(x, val, sizeof x)
typedef pair<ll, int> PII;
int cnt, head[maxn];
struct node {
    int u, v, nex;
    ll w;
} e[maxn << 1];
void init() {
    Clear(head, -1);
    cnt = 0;
}
void add(int u, int v, ll w) {
    e[cnt].u   = u;
    e[cnt].v   = v;
    e[cnt].w   = w;
    e[cnt].nex = head[u];
    head[u]    = cnt++;
}
ll dis[maxn];
bool vis[maxn];
void Dijkstra(int x) {
    memset(dis, 0x3f3f3f3f, sizeof dis);
    Clear(vis, 0);
    dis[x] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> que;
    que.push({dis[x], x});
    while (que.size()) {
        PII top = que.top();
        que.pop();
        ll w    = top.first;
        int u   = top.second;
        if (vis[u]) continue;
        vis[u] = 1;
        for (int i = head[u]; ~i; i = e[i].nex) {
            int to = e[i].v;
            if (dis[to] > w + e[i].w) {
                dis[to] = dis[u] + e[i].w;
                if (!vis[to]) {
                    que.push({dis[to], to});
                }
            }
        }
    }
}
ll cost[maxn];
ll dis2[maxn];
int n;
int main() {
    n = read;
    init();
    for (int i = 1; i < n; i++) {
        int u = read, v = read;
        ll w = read;
        add(u, v, w);
        add(v, u, w);
    }
    for (int i = 1; i <= n; i++) cost[i] = read;
    Dijkstra(1);
    ll mx   = -1;
    int pos = 0;
    for (int i = 1; i <= n; i++) {
        if (i == 1) continue;
        if (cost[i] + dis[i] > mx) {
            mx  = cost[i] + dis[i];
            pos = i;
        }
    }
    Dijkstra(pos);
    int pos2 = 0;
    mx       = -1;
    for (int i = 1; i <= n; i++) {
        if (i == pos) continue;
        if (cost[i] + dis[i] > mx) {
            mx   = cost[i] + dis[i];
            pos2 = i;
        }
    }
    /// the long_est one is from pos to pos2
    Dijkstra(pos);
    for (int i = 1; i <= n; i++) dis2[i] = dis[i];
    Dijkstra(pos2);
    for (int i = 1; i <= n; i++) {
        ll out = 0;
        if (i != pos) out = max(out, dis2[i] + cost[pos]);
        if (i != pos2) out = max(out, dis[i] + cost[pos2]);
        cout << out << endl;
    }
    return 0;
}




目录
相关文章
|
4月前
|
人工智能 BI
【每日一题Day267】LC834树中距离之和 | 换根dp
【每日一题Day267】LC834树中距离之和 | 换根dp
22 0
|
6月前
|
人工智能 算法 测试技术
华为机试HJ52:计算字符串的距离(动态规划)
华为机试HJ52:计算字符串的距离(动态规划)
|
10月前
|
算法
转:用一个例子说明Floyd算法
弗洛伊德算法(Floyd&#39;s algorithm)是一种用于求带权图中最短路径的算法,适用于带有正负权边的图(但不能有负环)。这种算法也有时被称为弗洛伊德-沃尔什算法。该算法基于动态规划,其时间复杂度为O(V^3),其中V是图中的顶点数。此外,该算法还可用于检测图中的负环并求出传递闭包。
86 2
|
11月前
|
机器学习/深度学习
51nod 1405 树的距离之和 (树形dp)
51nod 1405 树的距离之和 (树形dp)
54 0
|
存储
【每日一题Day106】LC1129 颜色交替的最短路径 | BFS
返回长度为 n 的数组 answer,其中 answer[X] 是从节点 0 到节点 X 的红色边和蓝色边交替出现的最短路径的长度。如果不存在这样的路径,那么 answer[x] = -1。
131 0
【CCCC】L3-008 喊山 (30分),BFS搜索最长路,水题
【CCCC】L3-008 喊山 (30分),BFS搜索最长路,水题
85 0
【CCCC】L3-018 森森美图 (30分),计算几何+判断三点共线+bfs最短路
【CCCC】L3-018 森森美图 (30分),计算几何+判断三点共线+bfs最短路
113 0
|
SQL Shell
HDU-4348 To the moon(主席树区间修改 永久化标记)
HDU-4348 To the moon(主席树区间修改 永久化标记)
116 0
HDU-4348 To the moon(主席树区间修改 永久化标记)
AtCoder Beginner Contest 216 D - Pair of Balls (思维建图 拓扑排序判断有向图是否有环)
AtCoder Beginner Contest 216 D - Pair of Balls (思维建图 拓扑排序判断有向图是否有环)
88 0
UPC Graph (最小生成树 || 并查集+二分)
UPC Graph (最小生成树 || 并查集+二分)
69 0