Codeforces 828F Best Edge Weight - 随机堆 - 树差分 - Kruskal - 倍增算法
You are given a connected weighted graph with n vertices and m edges. The graph doesn't contain loops nor multiple edges. Consider some edge with id i. Let's determine for this edge the maximum integer weight we can give to it so that it is contained in all minimum spanning trees of the graph if we don't change the other weights.
You are to determine this maximum weight described above for each edge. You should calculate the answer for each edge independently, it means there can't be two edges with changed weights at the same time.
The first line contains two integers n and m (2 ≤ n ≤ 2·105, n - 1 ≤ m ≤ 2·105), where n and m are the number of vertices and the number of edges in the graph, respectively.
Each of the next m lines contains three integers u, v and c (1 ≤ v, u ≤ n, v ≠ u, 1 ≤ c ≤ 109) meaning that there is an edge between vertices u and v with weight c.
Print the answer for each edge in the order the edges are given in the input. If an edge is contained in every minimum spanning tree with any weight, print -1 as the answer.
4 4
1 2 2
2 3 2
3 4 2
4 1 3
2 2 2 1
4 3
1 2 2
2 3 2
3 4 2
-1 -1 -1
题目大意 给定一个无向连通带权图,求每条边在所有最小生成树中的最大权值(如果可以无限大就输出-1)。
对于求1条边在无向连通图带权图的所有最小生成树中的最大权值可以用二分再用Kruskal进行check,但是如果每条边都这么做就会T掉。
所以考虑整体二分,然而并不行。
所以考虑先跑一遍Kruskal,然后分类讨论一下:
1)考虑一条非树边可以取的最大权值。
考虑把它加入树中,那么会形成1个环,为了保证最小生成树的边权和最小,方法是删掉环上权值最大的一条边。
所以找到它连接的两端在树上形成的简单路径中边权最大的一个,它的边权-1就是这条非树边的答案。
这个操作可以用树链剖分或者倍增解决。
2)考虑一条树边可以取到的最大权值
具体考虑一条树边会比较难做(不过好像有同学设计了时间戳把它搞定了),但是对于每条非树边都会对它连接的两端在树上形成的简单路径上的所有边有个边权的限制,就是不能超过它的边权 - 1,否则会被它替换掉。
这个区间取min操作可以用树链剖分。然而考试的时候我脑子瓦特了,觉得线段树不能区间取min(可能是脑补了一个求和操作)
然后想到了只有到最后会一起求得树边的答案,于是想到了差分。
为了维护这个最小值,又想到了可并堆。由于要删除,所以可以用下面这个方法构造可删堆(一位dalao的博客提到这个黑科技,我就学习了一下)
再开一个堆记录要删除的元素,如果两个堆堆顶元素相同,则都弹出堆顶元素。
于是便又有一个名为树差分 + 可并堆的zz做法。
Code
/**
* Codeforces
* Problem#828F
* Accepted
* Time: 420ms
* Memory: 57864k
*/
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <vector>
#include <bitset>
#ifdef WIN32
#define Auto "%I64d"
#else
#define Auto "%lld"
#endif
using namespace std;
typedef bool boolean;
#define ll int
#define smin(_a, _b) _a = min(_a, _b)
#define smax(_a, _b) _a = max(_a, _b)
#define fi first
#define sc second
const signed int inf = (signed) (~0u >> );
const signed ll llf = (signed ll) (~0ull >> );
typedef pair<int, int> pii; template<typename T>
inline void readInteger(T& u) {
static char x;
while(!isdigit(x = getchar()));
for(u = x - ''; isdigit(x = getchar()); u = u * + x - '');
} template<typename T>
class Matrix {
public:
T* p;
int row;
int col;
Matrix():p(NULL) { }
Matrix(int row, int col):row(row), col(col) {
p = new T[(row * col)];
} T* operator [] (int pos) {
return p + (pos * col);
}
};
#define matset(a, i, s) memset(a.p, i, sizeof(s) * a.row * a.col) typedef class Edge {
public:
int u;
int v;
int w;
boolean seced;
int rid; Edge(int u = , int v = , int w = ):u(u), v(v), w(w), seced(false) { } boolean operator < (Edge b) const {
return w < b.w;
}
}Edge; typedef class Node {
public:
int val;
Node *nxt[]; Node(int val = inf):val(val) { nxt[] = nxt[] = NULL; }
}Node; typedef pair<Node*, Node*> pnn;
#define limit 1000000 Node pool[limit];
Node *top = pool; Node* newnode(int x) {
if(top == pool + limit)
return new Node(x);
*top = Node(x);
return top++;
} Node* merge(Node* &l, Node* r) {
if(l == NULL) return r;
if(r == NULL) return l;
if(l->val > r->val) swap(l, r);
int p = rand() % ;
l->nxt[p] = merge(l->nxt[p], r);
return l;
} int n, m;
Edge* edge;
int* res;
int* ans; inline void init() {
readInteger(n);
readInteger(m);
edge = new Edge[(m + )];
for(int i = ; i <= m; i++) {
readInteger(edge[i].u);
readInteger(edge[i].v);
readInteger(edge[i].w);
edge[i].rid = i;
}
} int *f; int find(int x) {
return (f[x] != x) ? (f[x] = find(f[x])) : (x);
} vector<int> *g;
vector<int> *add;
vector<int> *del; inline void Kruskal() {
f = new int[(n + )];
g = new vector<int>[(n + )];
for(int i = ; i <= n; i++)
f[i] = i;
sort(edge + , edge + m + );
int fin = ;
for(int i = ; i <= m && fin < n - ; i++) {
if(find(edge[i].u) != find(edge[i].v)) {
f[find(edge[i].u)] = find(edge[i].v);
g[edge[i].u].push_back(i);
g[edge[i].v].push_back(i);
edge[i].seced = true;
fin++;
}
}
} const int BZMAX = ;
int* dep;
Matrix<int> bz;
Matrix<int> bzm; void dfs1(int node, int fa, int lastv) {
dep[node] = dep[fa] + ;
bz[node][] = fa;
bzm[node][] = lastv;
for(int i = ; i < BZMAX; i++)
bz[node][i] = bz[bz[node][i - ]][i - ], bzm[node][i] = max(bzm[node][i - ], bzm[bz[node][i - ]][i - ]);
for(int i = ; i < (signed)g[node].size(); i++) {
if(!edge[g[node][i]].seced) continue;
int e = (edge[g[node][i]].u == node) ? (edge[g[node][i]].v) : (edge[g[node][i]].u);
if(e == fa) continue;
dfs1(e, node, edge[g[node][i]].w);
}
} pii lca(int u, int v) {
if(dep[u] < dep[v]) swap(u, v);
int rtmax = ;
int ca = dep[u] - dep[v];
for(int i = ; i < BZMAX; i++)
if(ca & ( << i)) {
smax(rtmax, bzm[u][i]);
u = bz[u][i];
}
if(u == v) return pii(u, rtmax);
for(int i = BZMAX - ; ~i; i--) {
if(bz[u][i] != bz[v][i]) {
smax(rtmax, bzm[u][i]);
smax(rtmax, bzm[v][i]);
u = bz[u][i];
v = bz[v][i];
}
}
smax(rtmax, bzm[u][]);
smax(rtmax, bzm[v][]);
return pii(bz[u][], rtmax);
} pair<Node*, Node*> dfs2(int node, int fa, int tofa) {
Node* rt = NULL;
Node* dl = NULL;
for(int i = ; i < (signed)g[node].size(); i++) {
if(!edge[g[node][i]].seced) continue;
int e = (edge[g[node][i]].u == node) ? (edge[g[node][i]].v) : (edge[g[node][i]].u);
if(e == fa) continue;
pnn ap = dfs2(e, node, g[node][i]);
rt = merge(rt, ap.fi);
dl = merge(dl, ap.sc);
}
for(int i = ; i < (signed)add[node].size(); i++)
rt = merge(rt, newnode(add[node][i]));
for(int i = ; i < (signed)del[node].size(); i++)
dl = merge(dl, newnode(del[node][i]));
while(dl && rt->val == dl->val) {
rt = merge(rt->nxt[], rt->nxt[]);
rt = merge(rt->nxt[], rt->nxt[]);
dl = merge(dl->nxt[], dl->nxt[]);
}
res[tofa] = (!rt) ? (-) : (rt->val);
return pnn(rt, dl);
} inline void solve() {
res = new int[(m + )];
dep = new int[(n + )];
bz = Matrix<int>(n + , BZMAX);
bzm = Matrix<int>(n + , BZMAX);
dep[] = ;
for(int i = ; i < BZMAX; i++)
bz[][i] = bzm[][i] = ;
dfs1(, , );
add = new vector<int>[(n + )];
del = new vector<int>[(n + )];
for(int i = ; i <= m; i++) {
if(edge[i].seced) continue;
int u = edge[i].u, v = edge[i].v;
pii l = lca(u, v);
res[i] = l.sc - ;
add[u].push_back(edge[i].w - );
add[v].push_back(edge[i].w - );
del[l.fi].push_back(edge[i].w - );
}
dfs2(, , );
ans = new int[(m + )];
for(int i = ; i <= m; i++)
ans[edge[i].rid] = res[i];
for(int i = ; i <= m; i++)
printf("%d ", ans[i]);
} int main() {
srand();
init();
Kruskal();
solve();
return ;
}
Codeforces 828F Best Edge Weight - 随机堆 - 树差分 - Kruskal - 倍增算法的更多相关文章
- codeforces 1017C - Cloud Computing 权值线段树 差分 贪心
https://codeforces.com/problemset/problem/1070/C 题意: 有很多活动,每个活动可以在天数为$[l,r]$时,提供$C$个价格为$P$的商品 现在从第一天 ...
- 【CodeForces】827 D. Best Edge Weight 最小生成树+倍增LCA+并查集
[题目]D. Best Edge Weight [题意]给定n个点m条边的带边权无向连通图,对每条边求最大边权,满足其他边权不变的前提下图的任意最小生成树都经过它.n,m<=2*10^5,1&l ...
- CF#633 D. Edge Weight Assignment
D. Edge Weight Assignment 题意 给出一个n个节点的树,现在要为边赋权值,使得任意两个叶子节点之间的路径权值异或和为0,问最多,最少有多少个不同的权值. 题解 最大值: 两个叶 ...
- CF 633 div1 1338 B. Edge Weight Assignment 构造
LINK:Edge Weight Assignment 这场当时没打 看到这个B题吓到我了 还好当时没打. 想了20min才知道怎么做 而且还不能证明. 首先考虑求最小. 可以发现 如果任意两个叶子节 ...
- cf827D Best Edge Weight (kruskal+倍增lca+并查集)
先用kruskal处理出一个最小生成树 对于非树边,倍增找出两端点间的最大边权-1就是答案 对于树边,如果它能被替代,就要有一条非树边,两端点在树上的路径覆盖了这条树边,而且边权不大于这条树边 这里可 ...
- [Codeforces 266E]More Queries to Array...(线段树+二项式定理)
[Codeforces 266E]More Queries to Array...(线段树+二项式定理) 题面 维护一个长度为\(n\)的序列\(a\),\(m\)个操作 区间赋值为\(x\) 查询\ ...
- [Codeforces 280D]k-Maximum Subsequence Sum(线段树)
[Codeforces 280D]k-Maximum Subsequence Sum(线段树) 题面 给出一个序列,序列里面的数有正有负,有两种操作 1.单点修改 2.区间查询,在区间中选出至多k个不 ...
- codeforces 1217E E. Sum Queries? (线段树
codeforces 1217E E. Sum Queries? (线段树 传送门:https://codeforces.com/contest/1217/problem/E 题意: n个数,m次询问 ...
- treap(堆树)
# 2018-09-27 17:35:58 我实现的这个treap不能算是堆.有问题 最近对堆这种结构有点感兴趣,然后想用指针的方式实现一个堆而不是利用数组这种结构,于是自己想到了一个用二叉树结构实现 ...
随机推荐
- 使用Nexus3搭建Maven私服+上传第三方jar包到本地maven仓库
1.搭建Maven私服背景 公司还是按捺不住,要搭建一个自己的Maven本地仓库,可以让开发人员down架包,从内网还是快很多. 这样公司的maven本地仓库就是 开发人员自己电脑上的maven仓库 ...
- 【JVM】CMS垃圾回收器
一.简介 Concurrent Mark Sweep,是一种以获取最短回收停顿时间为目标的收集器,尤其重视服务的响应速度. CMS是老年代垃圾回收器,基于标记-清除算法实现.新生代默认使用ParNew ...
- DataPipeline CTO陈肃:构建批流一体数据融合平台的一致性语义保证
文 | 陈肃 DataPipelineCTO 交流微信 | datapipeline2018 本文完整PPT获取 | 关注公众号后,后台回复“陈肃” 首先,本文将从数据融合角度,谈一下DataPipe ...
- uni-app结合PHP实现单用户登陆
单用户登陆,即在一个应用中,同一个用户只能在线登陆一个,一个用户登陆,在其他设备上会被即时挤下线,确认后清空登陆该设备上的登陆装填并退回到登陆界面. uni-app是目前能通过使用vue.js框架只需 ...
- JDBC连接时出现的两个错误
这两个错误都是因为版本的更新导致的: 错误代码: package FirstTest; import java.sql.*; public class FirstJDBC { public stati ...
- MySQL 5.7数据库参数优化
连接相关参数 max_connections:允许客户端并发连接的最大数量,默认值是151,一般将该参数设置为500-2000max_connect_errors:如果客户端尝试连接的错误数量超过这个 ...
- 如何处理动态JSON in Go
假如要设计一个统计的json解析模块,json格式为 { "type": "用来识别不同的json数据", "msg": "嵌套的 ...
- maven nexus 私服搭建 Windows版
准备工作 已安装jdk,并配置好了环境变量 已安装maven,并配置好了环境变量 下载Nexus Repository OSS:https://www.sonatype.com/download-os ...
- 洛谷 P1330 封锁阳光大学题解
题目描述 曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街.河蟹看到欢快的曹,感到不爽.河蟹决定封锁阳光大学,不让曹刷街. 阳光大学的校园是一张由N个点构成的无向图,N个点之间由M ...
- HDU6625: three arrays (字典树处理xor)
题意:给出A数组,B数组,你可以对A和B分别进行重排列,使得C[i]=A[i]^B[i]的字典序最小. 思路:对于这类题,显然需要建立字典树,然后某种形式取分治,或者贪心. 假设现在有了两颗字典树A ...