BZOJ 1977 次小生成树
题目大意:
求严格次小生成树(权值和严格小于最小生成树)
题目分析:
和无限制的次小生成树一样,唯一不同的是,严格小于,只需要将删除非树边连接的两点树链上的最长边改为删除1.如果最长边不等于该边,就直接计算2.如果等于,就用次长边计算。
在最小生成树上倍增即可。
code
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>
inline T read(){
T i = 0, f = 1; char ch = getchar();
for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
if(ch == '-') ch = getchar(), f = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
return i * f;
}
template<typename T>
inline void wr(T x){
if(x < 0) putchar('-'), x= - x;
if(x > 9) wr(x / 10);
putchar(x % 10 + '0');
}
}using namespace IO;
const int N = 1e5+5, M = 3e5+5;
const long long OO = 2e18;
long long ans1 = 0, ans2 = OO;
int n, m;
int ecnt, adj[N], nxt[M << 1], go[M << 1], len[M <<1];
int anc[N], dep[N];
int fa[N][25];
long long maxx[N][25];
bool used[M];
struct node{
int x, y, c;
inline bool operator < (const node &b) const{
return c < b.c;
}
inline void load(){
x = read<int>(), y = read<int>(), c = read<int>();
}
}edge[M];
inline void addEdge(int u, int v, int c){
nxt[++ecnt] = adj[u], adj[u] = ecnt, go[ecnt] = v, len[ecnt] = c;
}
inline int getAnc(int x){
return x == anc[x] ? x : (anc[x] = getAnc(anc[x]));
}
inline void dfs(int u, int f, int ee){
fa[u][0] = f;
dep[u] = dep[f] + 1;
maxx[u][0] = len[ee];
for(int i = 1; i <= 20; i++){
fa[u][i] = fa[fa[u][i - 1]][i - 1];
maxx[u][i] = max(maxx[u][i - 1], maxx[fa[u][i - 1]][i - 1]);
}
for(int e = adj[u]; e; e = nxt[e]){
int v = go[e];
if(v == f) continue;
dfs(v, u, e);
}
}
inline pair<long long, long long> get(int u, int v){
//int lca = getLca(u, v);
long long ma1 = -OO, ma2 = -OO;
if(dep[u] < dep[v]) swap(u, v);
int delta = dep[u] - dep[v];
for(int i = 20; i >= 0; i--){
if(delta & (1 << i)){
if(maxx[u][i] > ma1){
ma2 = ma1;
ma1 = maxx[u][i];
}
else if(maxx[u][i] > ma2)
ma2 = maxx[u][i];
u = fa[u][i];
}
}
if(u == v) return make_pair(ma1, ma2);
for(int i = 20; i >= 0; i--){
if(fa[u][i] != fa[v][i]){
if(maxx[v][i] > ma1){
ma2 = ma1;
ma1 = maxx[v][i];
}
else if(maxx[v][i] > ma2)
ma2 = maxx[v][i];
v = fa[v][i];
//-----------------------------
if(maxx[u][i] > ma1){
ma2 = ma1;
ma1 = maxx[u][i];
}
else if(maxx[u][i] > ma2)
ma2 = maxx[u][i];
u = fa[u][i];
}
}
if(maxx[v][0] > ma1){
ma2 = ma1;
ma1 = maxx[v][0];
}
else if(maxx[v][0] > ma2)
ma2 = maxx[v][0];
//-----------------------------
if(maxx[u][0] > ma1){
ma2 = ma1;
ma1 = maxx[u][0];
}
else if(maxx[u][0] > ma2)
ma2 = maxx[u][0];
return make_pair(ma1, ma2);
}
int main(){
freopen("h.in", "r", stdin);
n = read<int>(), m = read<int>();
for(int i = 1; i <= n; i++) anc[i] = i;
for(int i = 1; i <= m; i++)
edge[i].load();
sort(edge + 1, edge + m + 1);
for(int i = 1; i <= m; i++){
int fx = getAnc(edge[i].x), fy = getAnc(edge[i].y);
if(fx != fy){
anc[fx] = fy;
ans1 += 1ll*edge[i].c;
addEdge(edge[i].x, edge[i].y, edge[i].c);
addEdge(edge[i].y, edge[i].x, edge[i].c);
used[i] = true;
}
}
for(int i = 1; i <= n; i++)
for(int j = 0; j <= 25; j++)
maxx[i][j] = OO;
dfs(1, 0, 0);
for(int i = 1; i <= m; i++){
if(used[i]) continue;
pair<int, int> ret = get(edge[i].x, edge[i].y);
//cout<<edge[i].x<<" "<<edge[i].y<<" "<<ret.first<<" "<<ret.second<<endl;
int delta = ret.first == edge[i].c ? ret.second : ret.first;
ans2 = min(ans2, ans1 - delta + edge[i].c);
}
printf("%lld", ans2);
return 0;
}