bzoj3206 [Apio2013]道路费用

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3206

http://uoj.ac/problem/108

【题解】

我们发现可以先硬点给的边一定选,做一遍最小生成树,得到的其他边就是一定选的。

然后可以缩点了,图的大小是K。

我们枚举选择那些硬点的边。

我们先把硬点的边,加上新的连接连通块的边,这些边组成了一棵树。K+1个点K条边。

考虑我们有一条硬点的边,那么对于每条有用的边(u,v),u到v的路径上的值都不能超过(u,v)的值(考虑kruskal过程)

然后我们暴力维护每条边的值即可。。

你写倍增我不拦你呀qwq

复杂度O(mlogm+2^kk^2)

# include <stdio.h>
# include <string.h>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 5e5 + 10, N = 70;

# define RG register
# define ST static

int n, m, K;
ll ans = 0;
struct edge{
    int u, v, w;
    friend bool operator < (edge a, edge b) {
        return a.w < b.w;
    }
}a[M], b[N], e[M]; int en = 0;
ll v[M], sum[M];

bool ok[M];
int res[M], resn = 0, S;

struct unionset {
    int fa[M];
    inline void set() {
        for (int i=1; i<=n; ++i) fa[i] = i;
    }
    inline int getf(int x) {
        return fa[x] == x ? x : fa[x] = getf(fa[x]);
    }
}A, B;
int fa[M], mi[M], dep[M];

int head[M], nxt[M], to[M], tot;
inline void add(int u, int v) {
    ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v;
}
inline void adde(int u, int v) {
    add(u, v), add(v, u);
}

inline void dfs(int x, int fat = 0) {
    fa[x] = fat; dep[x] = dep[fat] + 1; sum[x] = v[x];
    for (int i=head[x]; i; i=nxt[i]) {
        if(to[i] == fat) continue;
        dfs(to[i], x);
        sum[x] += sum[to[i]];
    }
}

inline void solve(int sta) {
    tot = 0;
    
//    printf("status = %d\n", sta);
    
    for (int i=1; i<=resn; ++i) {
        int x = res[i]; head[x] = 0;
        A.fa[x] = x; fa[x] = 0;
        mi[x] = 1e9;
    }
    for (int i=1; i<=K; ++i)
        if(sta & (1<<(i-1))) ok[i] = 1;
        else ok[i] = 0;
    
    for (int i=1; i<=K; ++i)
        if(ok[i]) {
            int u = A.getf(b[i].u), v = A.getf(b[i].v);
            if(u == v) return ;      //
            A.fa[u] = v; adde(b[i].u, b[i].v);
        }
    
    for (int i=1; i<=en; ++i) {
        int u = A.getf(e[i].u), v = A.getf(e[i].v);
        if(u == v) continue;
        A.fa[u] = v;
        adde(e[i].u, e[i].v);
    }
    
    dfs(S);
    
    for (int i=1; i<=en; ++i) {
        int u = e[i].u, v = e[i].v;
        if(dep[u] < dep[v]) swap(u, v); 
        while(dep[u] != dep[v]) {
            mi[u] = min(mi[u], e[i].w);
            u = fa[u];
        }
        while(u != v) {
            mi[u] = min(mi[u], e[i].w);
            mi[v] = min(mi[v], e[i].w);
            u = fa[u], v = fa[v];
        }
    }
    
    ll cur = 0;
    for (int i=1; i<=K; ++i) {
        if(ok[i]) {
            int u = b[i].u, v = b[i].v;
            if(dep[u] < dep[v]) swap(u, v);
            cur += sum[u] * mi[u];
        }
    }
    if(cur > ans) ans = cur;
}

int main() {
    scanf("%d%d%d", &n, &m, &K);
    A.set(), B.set();
    for (int i=1; i<=m; ++i) scanf("%d%d%d", &a[i].u, &a[i].v, &a[i].w);
    sort(a+1, a+m+1);
    for (int i=1; i<=K; ++i) {
        scanf("%d%d", &b[i].u, &b[i].v);
        int u = A.getf(b[i].u), v = A.getf(b[i].v);
        A.fa[u] = v;
    }
    for (int i=1; i<=m; ++i) { 
        int u = A.getf(a[i].u), v = A.getf(a[i].v);
        if(u != v) {
            A.fa[u] = v;
            u = B.getf(a[i].u), v = B.getf(a[i].v);
            B.fa[u] = v;
        }
    }
    S = B.getf(1);
    for (int i=1, t; i<=n; ++i) {
        scanf("%d", &t);
        v[B.getf(i)] += t;
        if(B.getf(i) == i)
            res[++resn] = i;
    }
    
    for (int i=1; i<=K; ++i) {
        b[i].u = B.getf(b[i].u);
        b[i].v = B.getf(b[i].v);
    }
    
    for (int i=1; i<=m; ++i) {
//        printf("====%d, %d\n", a[i].u, a[i].v);
        a[i].u = B.getf(a[i].u);
        a[i].v = B.getf(a[i].v);
//        printf("modified %d, %d\n", a[i].u, a[i].v);
    }
    for (int i=1; i<=m; ++i) {
        int u = B.getf(a[i].u), v = B.getf(a[i].v); 
        if(u != v) ok[i] = 1, B.fa[u] = v;
        else ok[i] = 0; 
    }
    for (int i=1; i<=m; ++i)
        if(ok[i]) e[++en] = a[i];
    
    for (int sta=0; sta < (1<<K); ++sta) solve(sta);
    
    printf("%lld\n", ans);
    
    return 0;
}
View Code

 

posted @ 2017-05-04 15:21  Galaxies  阅读(446)  评论(0编辑  收藏  举报