首先由贪心的想法知道,树边只减不加,非树边只加不减,令$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. MySQl的几个配置项

    对对于MySQL的日志功能,我们可以完全自己控制到底写还是不写.一般来说,binlog我们一般会开启,而对于慢查询我们一般会在开发的时候调试和观 察SQL语句的执行速度.但今天发现一个问题.在使用sh ...

  2. git学习笔记02-创建一个仓库提交一个文件-原来就是这么简单

    打开安装好的git bash,设置你的git信息  (这个随便写就行) 初始化一个Git仓库,分三步.(创建文件夹也可以手动创建,也可以命令行创建) 第一步,进到一个目录  cd e: 第二步,创建一 ...

  3. SQL笔记(1)索引/触发器

    --创建聚集索引 create clustered index ix_tbl_test_DocDate on tbl_test(DocDate) GO --创建非聚集索引 create nonclus ...

  4. bootstrap 手风琴效果

    <!DOCTYPE HTML> <html><head><meta charset="utf-8"><title>按钮插 ...

  5. Python学习(18)面向对象

    目录 Python 面向对象 创建实例对象 Python内置类属性 Pyyhon对象销毁(垃圾回收) 类属性与方法 Python 面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此 ...

  6. odoo中pos模块由于删除partner导致发生(你试图访问的单据已经删除)错误的解决方法

    model.js文件中 push_order: function(order) { var self = this; if(order){ this.proxy.log('push_order',or ...

  7. Java字符串处理函数

    substring() 它有两种形式,第一种是:String substring(int startIndex)第二种是:String substring(int startIndex,int end ...

  8. 认识Service

    Service相对于Activity可在后台运行,五显示界面,在activity退出的情况下仍能运行. 一.新建一个空的工程,命名为learnService 二.新建一个service,并添加如下所示 ...

  9. android学习---- WindowManager 接口 (

    The interface that apps use to talk to the window manager. 这个接口用于与 window manager (窗口管理器, 应用框架层) 进行交 ...

  10. hiho_1052_基因工程

    题目大意 给出一个字符串(长度<=1000),字符串中的字符均为ATCG中的某一个.给出一个数字K,通过更改字符串中的某些字符,可以使得字符串的前K个字符形成的子串和最后K个字符形成的子串相同, ...