首先由贪心的想法知道,树边只减不加,非树边只加不减,令$w_i$表示i号边原来的边权,$d_i$表示i号边的改变量

对于一条非树边$j$连接着两个点$x$、$y$,则对于$xy$这条路径上的所有树边$i$,都要满足:$w_i - d_i \le w_j + d_j$

移项可得$w_i -w_j \le d_i + d_j$

于是我们发现$d[]$就是KM算法里的顶标了,直接跑最大匹配即可

 /**************************************************************
Problem: 1937
User: rausen
Language: C++
Result: Accepted
Time:700 ms
Memory:4796 kb
****************************************************************/ #include <cstdio>
#include <cstring>
#include <algorithm> using namespace std;
const int N = ;
const int M = ;
const int inf = 1e9; inline int read(); struct edge {
int next, to, id;
edge(int _n = , int _t = , int _i = ) : next(_n), to(_t), id(_i) {}
} e[N << ]; struct Edge {
int x, y, v, f; inline void get() {
x = read(), y = read(), v = read(), f = ;
}
} E[M]; struct tree_node {
int dep, fa[], e;
} tr[N]; int n, m;
int first[N], tot;
int mp[M][M]; namespace KM {
int slack[M], lx[M], ly[M], linky[M];
bool visx[M], visy[M]; bool find(int x) {
int y, tmp;
for (visx[x] = y = ; y <= m; ++y) if (!visy[y]) {
tmp = lx[x] + ly[y] - mp[x][y];
if (tmp == ) {
visy[y] = ;
if (linky[y] == - || find(linky[y])) {
linky[y] = x;
return ;
}
} else
if (slack[y] > tmp) slack[y] = tmp;
}
return ;
} int work() {
static int i, j, x, d, res;
memset(linky, -, sizeof(linky));
memset(ly, , sizeof(ly));
for (i = ; i <= m; ++i)
for (j = , lx[i] = -inf; j <= m; ++j)
lx[i] = max(lx[i], mp[i][j]);
for (x = ; x <= m; ++x) {
for (i = ; i <= m; ++i)
slack[i] = inf;
while() {
memset(visx, , sizeof(visx));
memset(visy, , sizeof(visy));
if (find(x)) break;
d = inf;
for (i = ; i <= m; ++i)
if (!visy[i]) d = min(d, slack[i]);
for (i = ; i <= m; ++i)
if (visx[i]) lx[i] -= d;
for (i = ; i <= m; ++i)
if (visy[i]) ly[i] += d;
else slack[i] -= d;
}
}
for (res = , i = ; i <= m; ++i)
res += mp[linky[i]][i];
return res;
}
}; inline void Add_Edges(int x, int y, int id) {
e[++tot] = edge(first[x], y, id), first[x] = tot;
e[++tot] = edge(first[y], x, id), first[y] = tot;
} #define y e[x].to
inline void dfs(int p) {
int i, x;
tr[p].dep = tr[tr[p].fa[]].dep + ;
for (i = ; i <= ; ++i)
tr[p].fa[i] = tr[tr[p].fa[i - ]].fa[i - ];
for (x = first[p]; x; x = e[x].next)
if (y != tr[p].fa[]) {
tr[y].fa[] = p, tr[y].e = e[x].id;
dfs(y);
}
}
#undef y inline int lca(int x, int y) {
static int i;
if (tr[x].dep < tr[y].dep) swap(x, y);
for (i = ; ~i; --i)
if (tr[tr[x].fa[i]].dep >= tr[y].dep) x = tr[x].fa[i];
if (x == y) return x;
for (i = ; ~i; --i)
if (tr[x].fa[i] != tr[y].fa[i])
x = tr[x].fa[i], y = tr[y].fa[i];
return tr[x].fa[];
} inline void build(int x, int f, int e, int v) {
while (x != f)
mp[tr[x].e][e] = max(, E[tr[x].e].v - v), x = tr[x].fa[];
} int main() {
int i, j;
int x, y, f;
n = read(), m = read();
for (i = ; i <= m; ++i)
E[i].get();
for (i = ; i < n; ++i) {
x = read(), y = read();
for (j = ; j <= m; ++j)
if ((E[j].x == x && E[j].y == y) || (E[j].x == y && E[j].y == x)) {
E[j].f = ;
Add_Edges(x, y, j);
break;
}
}
dfs();
for (i = ; i <= m; ++i)
if (!E[i].f) {
x = E[i].x, y = E[i].y, f = lca(x, y);
build(x, f, i, E[i].v);
build(y, f, i, E[i].v);
}
printf("%d\n", KM::work());
return ;
} inline int read() {
static int x;
static char ch;
x = , ch = getchar();
while (ch < '' || '' < ch)
ch = getchar();
while ('' <= ch && ch <= '') {
x = x * + ch - '';
ch = getchar();
}
return x;
}

BZOJ1937 [Shoi2004]Mst 最小生成树的更多相关文章

  1. [BZOJ1937][SHOI2004]Mst最小生成树(KM算法,最大费用流)

    1937: [Shoi2004]Mst 最小生成树 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 802  Solved: 344[Submit][Sta ...

  2. 【KM】BZOJ1937 [Shoi2004]Mst 最小生成树

    这道题拖了好久因为懒,结果1A了,惊讶∑( 口 || [题目大意] 给定一张n个顶点m条边的有权无向图.现要修改各边边权,使得给出n-1条边是这张图的最小生成树,代价为变化量的绝对值.求最小代价之和. ...

  3. 【BZOJ1937】[Shoi2004]Mst 最小生成树 KM算法(线性规划)

    [BZOJ1937][Shoi2004]Mst 最小生成树 Description Input 第一行为N.M,其中 表示顶点的数目, 表示边的数目.顶点的编号为1.2.3.…….N-1.N.接下来的 ...

  4. 【bzoj1937】 Shoi2004—Mst 最小生成树

    http://www.lydsy.com/JudgeOnline/problem.php?id=1937 (题目链接) 题意 一个无向图,给出一个生成树,可以修改每条边的权值,问最小修改多少权值使得给 ...

  5. BZOJ 1937: [Shoi2004]Mst 最小生成树 [二分图最大权匹配]

    传送门 题意: 给一张无向图和一棵生成树,改变一些边的权值使生成树为最小生成树,代价为改变权值和的绝对值,求最小代价 线性规划的形式: $Min\quad \sum\limits_{i=1}^{m} ...

  6. [BZOJ 1937][Shoi2004]Mst 最小生成树

    传送门 $ \color{red} {solution:} $ 对于每条树边\(i\),其边权只可能变小,对于非树边\(j\),其边权只可能变大,所以对于任意非树边覆盖的树边有 \(wi - di & ...

  7. MST最小生成树

    首先,贴上一个很好的讲解贴: http://www.wutianqi.com/?p=3012 HDOJ 1233 还是畅通工程 http://acm.hdu.edu.cn/showproblem.ph ...

  8. [poj1679]The Unique MST(最小生成树)

    The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 28207   Accepted: 10073 ...

  9. UVA 1151 Buy or Build (MST最小生成树,kruscal,变形)

    题意: 要使n个点之间能够互通,要使两点直接互通需要耗费它们之间的欧几里得距离的平方大小的花费,这说明每两个点都可以使其互通.接着有q个套餐可以选,一旦选了这些套餐,他们所包含的点自动就连起来了,所需 ...

随机推荐

  1. 【CC评网】2013.第38周 要阅读 要有好工具

    要阅读,要有好工具 Reeder终于在ipad上推出了第二代版本,终于脱离了Google reader而独立存在: 自从Google reader关闭之后,我就在各种支持rss的阅读器中游荡,却总是找 ...

  2. MySQL数据表生成ER图

    遇到没有说明文档的数据库的时候,一张一张表去分析,需要花费很长时间和精力. 幸好有一些工具,可以帮助我们生成ER图,这样看起来就一目了然: 下面我将自己的一次实践记录于下,供参考: 1.下载并安装工具 ...

  3. Flex打印功能FlexPrintJob调用

    收藏下很详细的学习资料 http://wenku.baidu.com/view/b3d4f40702020740be1e9bf8.html import mx.printing.FlexPrintJo ...

  4. [转]-Gradle使用手册(二):项目结构

    原文地址:http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Using-sourceCompatibility-1. ...

  5. CSS的基本操作

    <html> <!-- . 给整个页面填一个一个背景 . 给em添加一个样式样倾斜效果消失 . 改变第一层UL的样式为蓝色,16px . 改变第二层的UL的样式为红色 14px . ...

  6. HDU-4518 吉哥系列故事——最终数 AC自动机+数位DP

    题意:如果一个数中的某一段是长度大于2的菲波那契数,那么这个数就被定义为F数,前几个F数是13,21,34,55......将这些数字进行编号,a1 = 13, a2 = 21.现给定一个数n,输出和 ...

  7. iOS - OC Struct 结构体

    1.结构体的定义与调用 // 定义结构体类型 // 结构体类型名为 MyDate1 struct MyDate1 { int year; int month; int day; }; // 定义结构体 ...

  8. iOS - UITextField

    前言 NS_CLASS_AVAILABLE_IOS(2_0) @interface UITextField : UIControl <UITextInput, NSCoding> @ava ...

  9. C# 上传RAR文件 解压 获取解压后的文件名称

    此方法适用于C盘windows文件夹中有WinRAR.exe文件 if (fileExt.ToUpper() == ".RAR") { string zpath = Server. ...

  10. NowCoder猜想(素数筛法+位压缩)

    在期末被各科的大作业碾压快要窒息之际,百忙之中抽空上牛客网逛了逛,无意中发现一道好题,NowCoder猜想,题意很明显,就是个简单的素数筛法,但竟然超内存了,我晕(+﹏+)~  明明有 3 万多 k ...