题意:给你一张n个节点和m条边的无向连通图, 你可以执行很多次操作,对某一条边的权值+1(对于每条边,可以不加,可以无限次加),问至少进行多少次操作,可以使这张图的最小生成树变得唯一,并且最小生成树的边权总和和原图的最小生成树一样。

思路:容易发现, 我们没必要给一条边反复加权值,最多加一次就够了,因为加一次就已经可能改变最小生成树的总边权了。所以,这个题换一种说法,就是问这张图有多少条边,加入最小生成树之后删掉一条其它的边也是最小生成树。

法1:我们首先可以把这颗最小生成树构造出来,然后暴力枚举每一条边,判断可不可以加到最小生成树中。假设这条边的端点是u, v,那么在树中就形成了一个环,为u  -> v -> LCA(u, v) -> u;我们只需要判断这条新加入的边是否比环中的其它边大就行了,不可能比环中的其它边的最大值小。因为如果这条边比环中边权最大的边小,那么删除边权最大的边就可以构成一颗更小的生成树,这不符合最小生成树的定义了,那么换句话说,我们构造出来的这棵树就不是最小生成树了。那么怎么找环上其它边的最大值呢?我们可以用倍增的思想,在倍增法求LCA的预处理时也可以把最值的预处理出来。查询最大值时套用LCA的框架更新最大值。

代码:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 200010;
struct Edge{
int u, v, w;
bool operator < (const Edge& rhs) const {
return w < rhs.w;
}
};
Edge edge[maxn];
int mx[maxn][20], f[maxn][20];
int t;
int head[maxn], Next[maxn * 2], edge1[maxn * 2], ver[maxn * 2], tot;
int fa[maxn], d[maxn];
queue<int> q;
bool v[maxn];
void add(int x, int y, int z) {
ver[++tot] = y;
edge1[tot] = z;
Next[tot] = head[x];
head[x] = tot;
} int get(int x) {
if(x == fa[x]) return x;
return fa[x] = get(fa[x]);
} void bfs() {
q.push(1);
d[1] = 1;
while(q.size()) {
int x = q.front();
q.pop();
for(int i = head[x]; i; i = Next[i]) {
int y = ver[i], z = edge1[i];
if(d[y]) continue;
d[y] = d[x] + 1;
f[y][0] = x;
mx[y][0] = z;
for(int j = 1; j <= t; j++) {
f[y][j] = f[f[y][j - 1]][j - 1];
mx[y][j] = max(mx[y][j - 1], mx[f[y][j - 1]][j - 1]);
}
q.push(y);
}
}
} int query(int x, int y) {
if(d[x] > d[y]) swap(x, y);
int ans = -INF;
for(int i = t; i >= 0; i--) {
if(d[f[y][i]] >= d[x]) {
ans = max(ans, mx[y][i]);
y = f[y][i];
}
}
if(x == y) return ans;
for(int i = t; i >= 0; i--) {
if(f[x][i] != f[y][i]) {
ans = max(ans, mx[x][i]);
ans = max(ans, mx[y][i]);
x = f[x][i];
y = f[y][i];
}
}
return max(ans, max(mx[x][0], mx[y][0]));
}
int main() {
int n, m;
// freopen("in.txt", "r", stdin);
scanf("%d%d", &n, &m);
t = (int)(log(n) / log(2)) + 1;
for(int i = 1; i <= m; i++) {
scanf("%d%d%d",&edge[i].u, &edge[i].v, &edge[i].w);
}
sort(edge + 1, edge + 1 + m);
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 1; i <= m; i++) {
int x = get(edge[i].u);
int y = get(edge[i].v);
if(x == y)continue;
fa[x] = y;
v[i] = 1;
add(edge[i].u, edge[i].v, edge[i].w);
add(edge[i].v, edge[i].u, edge[i].w);
}
bfs();
int ans = 0;
for(int i = 1; i <= m; i++) {
if(v[i])continue;
int tmp = query(edge[i].u, edge[i].v);
if(tmp == edge[i].w) ans++;
}
printf("%d\n", ans);
}

法2:对于边权相同的边,我们可以把它们分成2类,一类是不可能成为最小生成树的边的边(之前有更小的边已经形成了一条链了),一类是可能的边,只是有一些边运气比较好,成为了当前最小生成树的边。我们就可以统计这些“运气不好”的边,运气不好“的边数目总和就是最终答案。具体过程:对于边权相同的边,我们先找出本来就不可能的边,在找到那些能成为最小生成树的“幸运边”,剩下的就是“运气不好”的边了。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 200010;
struct Edge{
int u,v,w;
bool operator < (const Edge& rhs) const {
return w < rhs.w;
}
};
Edge edge[maxn];
int fa[maxn];
int get(int x) {
if(x == fa[x]) return x;
return fa[x] = get(fa[x]);
} bool merge(int x, int y) {
int tmp1 = get(x);
int tmp2 = get(y);
if(tmp1 == tmp2) return 0;
fa[tmp1] = tmp2;
return 1;
} int main() {
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++) {
scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
}
sort(edge + 1, edge + 1 + m);
for(int i = 1; i <= n; i++) fa[i] = i;
int ans = 0, sum = 0;
for(int i = 1; i <= m; i++) {
int j = i;
while(edge[j + 1].w == edge[j].w) j++;
sum = j - i + 1;
for(int k = i; k <= j; k++) {
if(get(edge[k].u) == get(edge[k].v))
sum--;
}
for(int k = i; k <= j; k++) {
sum -= merge(edge[k].u, edge[k].v);
}
ans += sum;
i = j;
}
printf("%d\n", ans);
}

  

Codeforces 1108F (MST Unification) (树上倍增 or 改进 kruksal)的更多相关文章

  1. Codeforces 1108F MST Unification MST + LCA

    Codeforces 1108F MST + LCA F. MST Unification Description: You are given an undirected weighted conn ...

  2. Codeforces 1108F MST Unification(最小生成树性质)

    题目链接:MST Unification 题意:给定一张连通的无向带权图.存在给边权加一的操作,求最少操作数,使得最小生成树唯一. 题解:最小生成树在算法导论中有这个性质: 把一个连通无向图的生成树边 ...

  3. Codeforces 609E (Kruskal求最小生成树+树上倍增求LCA)

    题面 传送门 题目大意: 给定一个无向连通带权图G,对于每条边(u,v,w)" role="presentation" style="position: rel ...

  4. 【CodeForces】983 E. NN country 树上倍增+二维数点

    [题目]E. NN country [题意]给定n个点的树和m条链,q次询问一条链(a,b)最少被多少条给定的链覆盖.\(n,m,q \leq 2*10^5\). [算法]树上倍增+二维数点(树状数组 ...

  5. [bzoj1977][BeiJing2010组队]次小生成树 Tree——树上倍增+lca

    Brief Description 求一个无向图的严格次小生成树. Algorithm Design 考察最小生成树的生成过程.对于一个非树边而言,如果我们使用这一条非树边去替换原MST的路径上的最大 ...

  6. Codevs 2370 小机房的树 LCA 树上倍增

    题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子, ...

  7. NOIP2013 货车运输 (最大生成树+树上倍增LCA)

    死磕一道题,中间发现倍增还是掌握的不熟 ,而且深刻理解:SB错误毁一生,憋了近2个小时才调对,不过还好一遍AC省了更多的事,不然我一定会疯掉的... 3287 货车运输 2013年NOIP全国联赛提高 ...

  8. HDU 4822 Tri-war(LCA树上倍增)(2013 Asia Regional Changchun)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4822 Problem Description Three countries, Red, Yellow ...

  9. [NOIP2013/Codevs3287]货车运输-最小[大]生成树-树上倍增

    Problem 树上倍增 题目大意 给出一个图,给出若干个点对u,v,求u,v的一条路径,该路径上最小的边权值最大. Solution 看到这个题第一反应是图论.. 然而,任意路径最小的边权值最大,如 ...

随机推荐

  1. 如何做好App的测试工作

    记得刚开始接触app测试时,可谓是一脸懵状,拿到一个功能不知道该测些什么,会因为测试范围确认不足.测试点考虑不全等导致线上问题,吃一堑才会长一智,栽过几次坑后就学会了如何避免.现总结App测试点如下, ...

  2. json与NSString转换

    json to string NSData *jsonData = [NSJSONSerialization dataWithJSONObject:json options:NSJSONWriting ...

  3. 下载 OS X 10.11 GM

    不清楚为什么OS X 10.11 GM版本是Coming Soon,可以通过下面简单方法启用App Store下载. 在终端执行: $ sudo softwareupdate --clear-cata ...

  4. 浅谈Vue个性化dashBoard 布局

    dashBoard布局在管理系统使用比较多:使用自己喜欢的方式进行自定义布局 使用npm 安装 npm install vue-grid-layout 全局使用 import vueGridLayou ...

  5. 解决win10 phptoshop #fff纯白不是这样的白 显示器高级的问题

    1.打开控制面板,右上角搜索栏输入“颜色管理”, 再打开“颜色管理”.2.在“设备”选项卡里,“设备”下拉列表,选择“显示器”.3.可能你安装过显示器的驱动程序,下面的配置文件中会有一个默认的配置文件 ...

  6. memcache内存分配问题

    Memcached是一个高效的分布式内存cache,了解memcached的内存管理机制,便于我们理解memcached,让我们可以针对我们数据特点进行调优,让其更好的为我所用.这里简单谈一下我对me ...

  7. SQL多表联查总结

    交叉连接:(不常用)返回两个表的笛卡尔乘积(也即全组合排列)中符合查询条件的数据行. 内连接返回连接表中符合连接条件和查询条件的数据行. 左外连接返回符合连接条件和查询条件(即:内连接)的数据行,且还 ...

  8. HihoCoder1403 后缀数组一·重复旋律1

    后缀数组一·重复旋律 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成的数列. 小Hi ...

  9. CAP理论、BASE理论

    从分布式一致性谈到CAP理论.BASE理论 https://www.cnblogs.com/szlbm/p/5588543.html 问题的提出 在计算机科学领域,分布式一致性是一个相当重要且被广泛探 ...

  10. 用HAWQ轻松取代传统数据仓库(八) —— 大表分区

    一.HAWQ中的分区表        与大多数关系数据库一样,HAWQ也支持分区表.这里所说的分区表是指HAWQ的内部分区表,外部分区表在后面“外部数据”篇讨论.在数据仓库应用中,事 实表通常有非常多 ...