BZOJ3246 [Ioi2013]Dreaming
构造 dp 贪心    2016-09-30 21:10:13    640    0    0
jszyxw   构造 dp 贪心

Description

Serpent(水蛇)生活的地方有N个水坑,编号为0,...,N - 1,有M条双向小路连接这些水坑。每两个水坑之间至多有一条路径(路径包含一条或多条小路)相互连接,有些水坑之间根本无法互通(即M ≤ N-1 )。Serpent走过每条小路需要一个固定的天数,不同的小路需要的天数可能不同。Serpent的朋友袋鼠希望新修 N - M - 1条小路,让Serpent可以在任何两个水坑间游走。袋鼠可以在任意两个水坑之间修路,Serpent通过每条新路的时间都是L天。袋鼠希望找到一种修路方式使得修路之后Serpent在每两个水坑之间游走的最长时间最短。

举例说明

上图中有12个水坑8条小路( N = 12, M = 8)。假如L = 2 ,即Serpent通过任何一条新路都需要2天。那么,袋鼠可以修建3条新路: 
水坑1和水坑2之间;
水坑1和水坑6之间;
水坑4和水坑10之间。

上图显示了修路后的最终状态。从水坑0走到水坑11的时间最长,需要18天。这是 最佳结果,无论袋鼠如何选择修路方式,总会存在一些水坑对,Serpent需要18天 或者更长时间从其中一个走到另一个。
 

 

Input

N : 水坑的数目。
M : 原本存在的小路的数目。
L : Serpent通过新修的路经的时间。
A, B 和 T: 三个包含M个元素的数组,分别表示每条小路的两个端点和通过这条小路的时间。例如,第i条小路连接水坑 A[i-1]和水坑B[i-1],通过这条小路的时间是T[i-1]天。
 
 

Output


如上所述,表示游走于两个距离最远的水坑之间所需的时间。

Sample Input

12 8 2
0 8 4
8 2 2
2 7 4
5 11 3
5 1 7
1 3 1
1 9 5
10 6 3

Sample Output

18

HINT

 

 n <= 500000

 

Solution

贪心地构造解....

先求出每棵树i中与其他点的距离最大值最小的点的最大距离dis[i],然后把所有树接向dis最大的树...

至于求dis,我们可以维护节点u到子树的距离的最大值dp[u][0]和次大值dp[u][1].

若u是fa[u]的最大距离所在的子树,则dp[u][0] = max(dp[fa[u]][1] + w[fa->u], dp[v] + w[u->v])

否则dp[u][0] = max(dp[fa[u]][0] + w[fa->u], dp[v] + w[u->v])

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 10;

template <class T> inline bool chkmax(T &x, T y) { return x < y ? x = y, true : false; }
template <class T> inline bool chkmin(T &x, T y) { return x > y ? x = y, true : false; }

inline void read(int &x)
{
    static char c;
    while (!isdigit(c = getchar())) ;
    for (x = 0; isdigit(c); c = getchar()) x = x * 10 + c - 48;
}

int n, m, len;

int st[maxn], cnte;
struct edge { int to, next, w; } e[maxn << 1];
inline void addedge(const int &u, const int &v, const int &w)
{
    e[++ cnte] = {v, st[u], w};
    st[u] = cnte;
}

int ans;
int mindis;
int son[maxn], dp[maxn][2], vis[maxn];

void dfs1(const int &x, const int &fa)
{
    vis[x] = 1;
    for (register int i = st[x]; i; i = e[i].next) {
        int v = e[i].to;
        if (v == fa) continue;
        dfs1(v, x);
        if (chkmax(dp[x][0], dp[v][0] + e[i].w))
            son[x] = v;
    }
    for (register int i = st[x]; i; i = e[i].next) {
        int v = e[i].to;
        if (v != fa && v != son[x])
            chkmax(dp[x][1], dp[v][0] + e[i].w);
    }
}

inline void dfs2(const int &x, const int &dis, const int &fa)
{
    if (dis > dp[x][0]) {
        dp[x][1] = dp[x][0];
        dp[x][0] = dis;
        son[x] = fa;
    }
    else
        chkmax(dp[x][1], dis);
    chkmin(mindis, dp[x][0]);
    chkmax(ans, dp[x][0]);
    for (register int i = st[x]; i; i = e[i].next) {
        int v = e[i].to;
        if (v != fa)
            dfs2(v, dp[x][v == son[x]] + e[i].w, x);
    }
}

int main()
{
    scanf("%d%d%d", &n, &m, &len);
    for (int i = 1; i <= m; ++ i) {
        static int u, v, w;
        read(u), read(v), read(w);
        ++ u; ++ v;
        addedge(u, v, w);
        addedge(v, u, w);
    }
    static int a[maxn], tot;
    for (register int i = 1; i <= n; ++ i) if (!vis[i]) {
        mindis = 0x3f3f3f3f;
        dfs1(i, 0);
        dfs2(i, 0, 0);
        a[++ tot] = mindis;
    }
    sort(a + 1, a + tot + 1);
    if (tot >= 2)
        chkmax(ans, a[tot] + a[tot - 1] + len);
    if (tot >= 3)
        chkmax(ans, a[tot - 1] + a[tot - 2] + 2 * len);
    printf("%d\n", ans);
}

 

2016.10.02省选模拟T4 travel
640 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航