首先由贪心的想法知道,树边只减不加,非树边只加不减,令$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. SQL:with ties

    摘自: http://www.cnblogs.com/huanghai223/archive/2010/10/26/1861961.html “从100万条记录中的得到成绩最高的记录”.看到这个题目, ...

  2. git学习笔记05-从远程库克隆

    现在,假设我们从零开发,那么最好的方式是先创建远程库,然后,从远程库克隆. 首先,登陆GitHub,创建一个新的仓库,名字叫gitskills: 我们勾选Initialize this reposit ...

  3. 几种HtmlEncode的区别(转)

    一.C#中的编码 HttpUtility.HtmlDecode.HttpUtility.HtmlEncode与Server.HtmlDecode.Server.HtmlEncode与HttpServe ...

  4. Linux的ldconfig和ldd用法

    ldd 查看程序依赖库 ldd 作用:用来查看程式运行所需的共享库,常用来解决程式因缺少某个库文件而不能运行的一些问题. 示例:查看test程序运行所依赖的库: /opt/app/todeav1/te ...

  5. Android 自定义列表指示器

    在联系人界面 可以看到这种界面 手指快速滑动右边滑动条时 可以显示相应的字母图标 android里提供了android.widget.SectionIndexer这个接口去实现该效果 可是只能显示字母 ...

  6. 让Fiddler能够检测到localhost的http数据

    用 vs.net开发调试网站程序时经常有这样的地址: http://localhost:2033/ 然而在开启 Fiddler 后会发现Fiddler 完全抓不到任何封包. 主要的原因是因为 Fidd ...

  7. oracle 生成随机数【待整理】

    http://www.cnblogs.com/ulex/p/4415478.html http://blog.sina.com.cn/s/blog_6a01140c0100wimi.html

  8. 华为 1.static有什么用途?(请至少说明两种)

    1.static有什么用途?(请至少说明两种) 1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变. 2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问 ...

  9. 有关使用Maven常见问题总结(Eclipse中使用Maven、Maven项目部署到tomcat等问题)

    http://blog.csdn.net/sunitjy/article/details/42709311 ********************************************** ...

  10. Freemarker 入门示例(zhuan)

    http://cuisuqiang.iteye.com/blog/2031768 ************************************ 初步学习freemarker ,先做一个简单 ...