http://codeforces.com/gym/101889

I

先跑一遍最小生成树,把经过的边和答案记录下来

对于每个询问的边,显然如果处于MST中,答案不变

如果不在MST中,假设这条边连上了,那么就会和原本的MST形成环,删除这个环中权值最大的边就是答案

处理的时候,可以用LCA维护MST:给出边的两个节点u、v,那么u和v的LCA路径上的最大值边就是环中权值最大的边

代码:

#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
const int MAX_V = 100005;
const int MAX_E = 200005;
const int MAX_N = 100005;
struct LCA_Online {
int N, M, E, root, in[MAX_N], head[MAX_N];
int f[MAX_N][30], c[MAX_N][30], depth[MAX_N];
struct Edge {
int to, next, cost;
} es[MAX_N << 2];
void addEdge(int u, int v, int w) {
es[E].to = v;
es[E].next = head[u];
es[E].cost = w;
head[u] = E++;
in[v]++;
}
void init(int N) {
this->N = N;
this->M = floor(log2(double(N)));
this->E = 0;
this->root = 0;
memset(head, -1, sizeof head);
memset(f, 0, sizeof f);
memset(c, 0, sizeof c);
memset(in, 0, sizeof in);
}
void dfs(int u) {
for (int j = 1; j <= M; j++) {
f[u][j] = f[f[u][j - 1]][j - 1];
c[u][j] = max(c[u][j - 1], c[f[u][j - 1]][j - 1]);
}
for (int i = head[u]; ~i; i = es[i].next) {
int v = es[i].to;
int w = es[i].cost;
if (v != f[u][0]) {
depth[v] = depth[u] + 1;
f[v][0] = u;
c[v][0] = w;
dfs(v);
}
}
}
void run() {
dfs(1);
}
int LCA(int u, int v) {
if (depth[u] < depth[v]) {
swap(u, v);
}
int res = 0;
int d = depth[u] - depth[v];
for (int i = 0; i <= M; i++) {
if ((1 << i) & d) {
res = max(res, c[u][i]);
u = f[u][i];
}
}
if (u == v) {
return res;
}
for (int i = M; i >= 0; i--) {
if (f[u][i] != f[v][i]) {
res = max(res, max(c[u][i], c[v][i]));
u = f[u][i];
v = f[v][i];
}
}
return max(res, max(c[u][0], c[v][0]));
}
} lca;
struct Kruskal {
struct Edge {
int from, to, cost;
bool operator< (const Edge& e) const {
return cost < e.cost;
}
} es[MAX_E];
int V, E, p[MAX_V];
void init(int V) {
this->V = V;
this->E = 0;
for (int i = 0; i < V; i++) {
p[i] = i;
}
}
void addEdge(int u, int v, int w) {
es[E].from = u;
es[E].to = v;
es[E].cost = w;
E++;
}
int find(int x) {
return x == p[x] ? x : p[x] = find(p[x]);
}
void unite(int x, int y) {
p[find(y)] = find(x);
}
ll kruskal() {
ll sum = 0;
sort(es, es + E);
for (int i = 0; i < E; i++) {
Edge &e = es[i];
if (find(e.from) != find(e.to)) {
sum += e.cost;
unite(e.from, e.to);
lca.addEdge(e.from, e.to, e.cost);
lca.addEdge(e.to, e.from, e.cost);
}
}
return sum;
}
} kru;
map<pair<int, int>, int> cost;
int main() {
int N, R, Q;
scanf("%d%d", &N, &R);
kru.init(N);
lca.init(N);
for (int i = 0, u, v, w; i < R; i++) {
scanf("%d%d%d", &u, &v, &w);
if (u > v) {
swap(u, v);
}
cost[make_pair(u, v)] = w;
//cost[make_pair(v, u)] = w;
kru.addEdge(u, v, w);
//kru.addEdge(v, u, w);
}
ll ans = kru.kruskal();
lca.run();
scanf("%d", &Q);
while (Q--) {
int u, v;
scanf("%d%d", &u, &v);
if (u > v) {
swap(u, v);
}
printf("%I64d\n", ans + cost[make_pair(u, v)] - lca.LCA(u, v));
}
}

【最小生成树+LCA】Imperial roads的更多相关文章

  1. gym 101889I Imperial roads 最小生成树+LCA

    题目传送门 题意: 给出一幅无向带权图,q次询问,每次询问都求一棵包含给出的边的最小生成树. 思路: 首先求出最小生成树(kruskal),如果查询的边在最小生成树上,肯定是直接输出最小生成树,如果不 ...

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

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

  3. kruskal算法求最小生成树(jungle roads的kruskal解法)

    注意: 注意数组越界问题(提交出现runtimeError代表数组越界) 刚开始提交的时候,边集中边的数目和点集中点的数目用的同一个宏定义,但是宏定义是按照点的最大数定义的,所以提交的时候出现了数组越 ...

  4. Drivers Dissatisfaction 最小生成树+LCA

    题意:给一张n个点m条边的连通图,每条边(ai,bi)有一个权值wi和费用ci, 表示这条边每降低1的权值需要ci的花费.现在一共有S费用可以用来降低某些边的权值 (可以降到负数),求图中的一棵权值和 ...

  5. [Codevs1519]过路费解题报告|最小生成树|LCA

    在某个遥远的国家里,有 n个城市.编号为 1,2,3,…,n.这个国家的政府修建了m 条双向道路,每条道路连接着两个城市.政府规定从城市 S 到城市T需要收取的过路费为所经过城市之间道路长度的最大值. ...

  6. 【BZOJ2238】Mst 最小生成树+LCA+堆

    [BZOJ2238]Mst Description 给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树.(各询问间独立,每次询问不对之后的询问产生影响,即被删掉的 ...

  7. 最小生成树:POJ1251-Jungle Roads(最小生成树的模板)

    POJ 1251 Jungle Roads >[poj原址:http://poj.org/problem?id=1251](http://poj.org/problem?id=1251) Des ...

  8. UVA - 11354Bond最小生成树,LCA寻找近期公共祖先

    看懂题目意思.他的意思是求将全部的城市走一遍,危急度最小.而且给 你两个s,t后让你求在走的时候,从s到t过程中危急度最大的值,并输出它, 然后就是怎样攻克了,这个题目能够说简单,也能够说难 通过思考 ...

  9. 最小生成树 D - Constructing Roads

    There are N villages, which are numbered from 1 to N, and you should build some roads such that ever ...

随机推荐

  1. linux、SMART、Shell的学习

    Linux指令 useradd 添加用户 添加用户 -d 添加用户路径 -e 制定密码有效时间 -G -g 指定用户所属组 -c 指定一段用户描述 -s Shell文件指定用户的登录Shell -u ...

  2. Java使用多线程实现Socket多客户端的通信

    要想详细了解socket,大家请自行百度,我这里只简单介绍. 在网络中,我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程.而socket编程就是为了完成两个唯一进程之间的通信(一个是客户端, ...

  3. thinkphp5查询表达式IN使用小计

    根据多个id批量更新指定字段值 $map[] = ['id','in', input('post.id/a')]; $result = db('picture')->where($map)-&g ...

  4. 服务器远程连接mysql问题解决

    一. centos下解决远程连接不上的问题. 1.查看centos 下防火墙是否关闭: 通过进程: ps -aux |grep firewalld ps -ef |grep firewalld 通过服 ...

  5. spark or sparkstreaming的内存泄露问题?

    关于sparkstreaming的无法正常产生数据---->到崩溃---->到数据读写极为缓慢(或块丢失?)问题 前两阶段请看我的博客:https://www.cnblogs.com/wa ...

  6. CAN总线的学习

    CAN(controller Area Network )总线的学习 1986 年德国电气商博世公司开发出面向汽车的CAN 通信协议(数据之间的交互),其目的是为适应“减少线束的数量”.“通过多个LA ...

  7. 【深度优先搜索】MZOJ_1344工作依赖

    这道题的读入非常毒瘤...恶心到我了 我痛苦地弄了很久,还是被卡住了我还真是▇了狗了.[传送门](特此声明:学校内部OJ,需登录) 题目描述(Description): 2008年,奥运会将在中国举行 ...

  8. rcosfir函数的用法

    B = rcosfir(R, N_T, RATE, T, FILTER_TYPE) designs and returns a square root raised cosine filter if ...

  9. 如何加入别人的Git项目——Git Fork指南

    如何加入别人的Git项目--Git Fork指南 首先,在网页打开别人Git上的项目,点击右上角的.下图因为Fork过了,所以灰了. 随即弹出如下窗口,当然选择确定. 于是,我们在在自己的项目列表可以 ...

  10. Linux Shell中的特殊符号和含义简明总结(包含了绝大部份)

    case语句适用于需要进行多重分支的应用情况. case分支语句的格式如下: case $变量名 in 模式1) 命令序列1 ;; 模式2) 命令序列2        ;; *) 默认执行的命令序列  ...