题目传送门

题意:

给出一幅无向带权图,q次询问,每次询问都求一棵包含给出的边的最小生成树。

思路:

首先求出最小生成树(kruskal),如果查询的边在最小生成树上,肯定是直接输出最小生成树,如果不在树上,那么这条必须连的边会和生成树形成一个环,我们就要去掉这个环上最大的一条边,就得到了答案(最小生成树是通过局部最优解得到全局最优解的,所以如果这样做,得到的是符合要求的最优解)。

赛中队友提出一个问题,如果有两棵不同的最小生成树那这个做法不就错了吗,但其实如果有两棵最小生成树,这两棵树 相同权值的边的条数是一样的,是同分异构,所以做法还是正确的。

而求环上的最大值,其实是求树上的最大值,所以在做kruskal的时候建立一幅新图,然后用lca求最大值。注意最大值的更新,很容易错。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#define CLR(a,b) memset(a,b,sizeof(a))
#define mkp(a,b) make_pair(a,b)
using namespace std;
const int maxn = ;
typedef long long ll;
int n, m, head[maxn], tot, vis[maxn],fa[maxn],deep[maxn],t,f[maxn][],ma[maxn][];
int ans;
struct edge {
int to, w, Next;
edge() {}
edge(int to, int Next, int w) :to(to), Next(Next), w(w) {}
}a[maxn * ];
map<pair<int, int >, int >mp;
struct node {
int u, v, w;
node(int u, int v, int w) :u(u), v(v), w(w) {}
};
vector<node>g;
void addv(int u, int v, int w) {
a[++tot] = { v,head[u],w };
head[u] = tot;
}
void init() {
CLR(head, -);
for (int i = ; i <= n; i++)fa[i] = i;
tot = ;
}
int find(int x)
{
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
inline void baba(int x, int y)
{
int fx = find(x), fy = find(y);
fa[fx] = fy;
}
bool cmp(node &a, node &b)
{
return a.w < b.w;
}
inline void kruskal() {
sort(g.begin(), g.end(), cmp);
for (int i = ; i < m; i++)
{
int x = find(g[i].u);
int y = find(g[i].v);
if (x == y)continue;
addv(g[i].u, g[i].v, g[i].w);
addv(g[i].v, g[i].u, g[i].w);
baba(x, y);
ans += g[i].w;
}
}
inline void bfs() {
queue<int >q;
q.push();
deep[] = ;
while (!q.empty())
{
int x = q.front();
q.pop();
for (int i = head[x]; i != -; i = a[i].Next)
{
int y = a[i].to;
if (deep[y])continue;
deep[y] = deep[x] + ;
f[y][] = x;
ma[y][] = a[i].w;
for (int j = ; j <= t; j++)
{
f[y][j] = f[f[y][j - ]][j - ];
ma[y][j] = max(ma[y][j-], ma[f[y][j - ]][j - ]);
}
q.push(y); }
}
}
int lca(int x, int y)
{
int maxx = ;
if (deep[x] > deep[y])swap(x, y);
for (int i = t; i >= ; i--)
{
if (deep[f[y][i]] >= deep[x]) {
maxx = max(maxx, ma[y][i]);
y = f[y][i];
}
}
if (x == y)return maxx;
for (int i = t; i >= ; i--)
{
if (f[x][i] != f[y][i]) {
maxx = max(maxx, ma[x][i]);
maxx = max(maxx, ma[y][i]);
x = f[x][i], y = f[y][i];
}
}
//printf("debug\n");
maxx=max(maxx,ma[x][]);
maxx=max(maxx,ma[y][]);
return maxx;
}
int main() {
scanf("%d%d", &n, &m);
init();
for(int i=;i<=m;i++)
{
int u, v;
int w;
scanf("%d%d%d", &u, &v, &w);
if (u > v)swap(u, v);
mp[make_pair(u, v)] = w;
g.push_back(node{ u,v,w });
}
kruskal();
t = (int)(log(n) / log()) + ;
bfs();
// for (int i = 1; i <= n; i++)
// {
// printf("i:%d deep:%d\n", i, deep[i]);
// }
int q;
cin >> q;
while (q--)
{
int u, v;
scanf("%d%d", &u, &v);
if (u > v)swap(u, v);
// printf("u:%d v:%d\n", u, v);
// printf("ans:%d lca:%d mp:%d\n",ans,lca(u,v),mp[make_pair(u,v)]);
printf("%d\n", ans - lca(u, v)+mp[make_pair(u,v)]);
}
} /* 5 7
1 2 6
1 3 4
3 4 2
1 5 7
4 5 4
2 4 1
3 5 3
1
4 5 */

gym 101889I Imperial roads 最小生成树+LCA的更多相关文章

  1. hdu Constructing Roads (最小生成树)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1102 /************************************************* ...

  2. 【最小生成树+LCA】Imperial roads

    http://codeforces.com/gym/101889 I 先跑一遍最小生成树,把经过的边和答案记录下来 对于每个询问的边,显然如果处于MST中,答案不变 如果不在MST中,假设这条边连上了 ...

  3. GYM 101889I(mst+lca)

    最小生成树上倍增询问裸的. const int maxn = 2e5 + 5; int n, m, q; //图 struct Edge { int u, v; ll cost; bool opera ...

  4. Gym - 101173H Hangar Hurdles (kruskal重构树/最小生成树+LCA)

    题目大意:给出一个n*n的矩阵,有一些点是障碍,给出Q组询问,每组询问求两点间能通过的最大正方形宽度. 首先需要求出以每个点(i,j)为中心的最大正方形宽度mxl[i][j],可以用二维前缀和+二分或 ...

  5. poj 1251 Jungle Roads (最小生成树)

    poj   1251  Jungle Roads  (最小生成树) Link: http://poj.org/problem?id=1251 Jungle Roads Time Limit: 1000 ...

  6. bzoj3732: Network--kruskal最小生成树+LCA

    这是一道写起来比较顺手的题目 没有各种奇怪的细节,基本就是Kruskal和倍增LCA的模板.. 题目大意:对于一个无向带权图,询问两点之间一条路,使得这条路上的最长边最小,输出最小最长边的的值 那么既 ...

  7. hdu 1301 Jungle Roads 最小生成树

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1301 The Head Elder of the tropical island of Lagrish ...

  8. HDU 1102 Constructing Roads (最小生成树)

    最小生成树模板(嗯……在kuangbin模板里面抄的……) 最小生成树(prim) /** Prim求MST * 耗费矩阵cost[][],标号从0开始,0~n-1 * 返回最小生成树的权值,返回-1 ...

  9. hdu Jungle Roads(最小生成树)

    Problem Description The Head Elder of the tropical island of Lagrishan has a problem. A burst of for ...

随机推荐

  1. CentOS6.5 增加交换空间

    在CentOS 6.5安装Oracle 11g的时候,提示交换空间不足,百度来下,找到来增加交换空间的方法,特此记录一下 增加交换空间有两种方法: 严格的说,在系统安装完后只有一种方法可以增加swap ...

  2. queue队列模块

    import Queue myqueue = Queue.Queue(maxsize = 10) Queue.Queue类即是一个队列的同步实现.队列长度可为无限或者有限.可通过Queue的构造函数的 ...

  3. apache重写规则详解

    RewriteEngine on 为重写引擎开关,如果设为off,则任何重写规则定义将不被应用,该开关的另一好处就是如果为了临时拿掉重写规则,则改为off再重启动Apache即可,不必将下面一条条的重 ...

  4. 【总结整理】dojo学习

    Dojo Toolkit 的特性可以分到 4 个不同部分.这种划分使得开发人员可以将库大小保持到最小,确保应用程序性能不受大量 JavaScript 库下载的影响.例如,如果您只需要 Ajax 支持性 ...

  5. newcoder中的基础题

    1. mysql_num_fields()  函数返回结果集中字段的数 2. <?php class A{ ; } $a = new A(); $b = $a; $a; echo $b-> ...

  6. 34- 24 Point game

    http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=43 24 Point game 时间限制:3000 ms  |  内存限制:65535 KB ...

  7. HDOJ 1164 Eddy's research

    上一篇已经讲了,但是转载别人的很乱,这里自己根据blog里面写的思路,重新写过了一个程序 #include <iostream> #include <malloc.h> #in ...

  8. 100722E The Bookcase

    传送门 题目大意 给你一些书的高度和宽度,有一个一列三行书柜,要求放进去书后,三行书柜的高的和乘以书柜的宽度最小.问这个值最小是多少. 分析 我们可以先将所有书按照高度降序排好,这样对于每一层只要放过 ...

  9. Bulma 源码解析之 .columns 类

    {说明} 这一部分的源码内容被我简化了,另外我还额外添加了一个辅助类 is-grow. .columns // 修饰类 &.is-centered justify-content: cente ...

  10. c# interface(接口)和abstract(抽象类)区别

    抽象类依然是一个类,不能被实例化,可以包含字段.成员变量.抽象方法.或者不抽象方法. 类继承抽象类,只重写抽象方法即可,其他是可以得到继承的. 接口是规则,里面只包含:方法.属性.索引.事件.类继承接 ...