zoukankan      html  css  js  c++  java
  • 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
    ", 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
    ", 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
    ", 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
    ", ans);
        
        return 0;
    }
    View Code
  • 相关阅读:
    ASP.NET 2.0 中动态添加 GridView 模板列的例子
    ASP操作Excel技术总结
    JS实现下拉列表效果
    发布无限制版CodePlusV2.0(转载)
    SQL行列转换(转载)
    [转]详解C中volatile关键字
    [转]68013开发笔记之一
    清除计算机占用串口
    modelsim保存仿真波形
    SQL存储过程分页算法研究(支持千万级) 转
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj3206.html
Copyright © 2011-2022 走看看