其他分享
首页 > 其他分享> > AcWing 356. 次小生成树

AcWing 356. 次小生成树

作者:互联网

分析

这题做法很简单:

上面的思路简单来说就是枚举非树边,加入满足替换后增量最小的边以得到答案。

实现

关键在于使用什么样的数据结构维护树上路径的最大值与次大值。

这里采用了线段树 + 树链剖分:

线段树的每个节点维护了一个最大值与次大值,这两个信息都是可以合并的,\(\texttt{merge}\) 函数见下:

Node merge(Node &L, Node &R){
	int rec[]={L.mx1, L.mx2, R.mx1, R.mx2};
	int mx1=-INF, mx2=-INF;
	for(auto i: rec) mx1=max(mx1, i); 
	rep(i,0,3) if(rec[i]!=mx1) mx2=max(mx2, rec[i]);
	return {L.l, R.r, mx1, mx2};
}

然后我们可以求出树上 \(u\to v\) 路径上的 \(LCA\),记为 \(a\)。

那么只需要对路径 \(u\to a\) 以及 \(v\to a\) 分别询问一次得到两条树链的信息(最大值、次大值)再合并这两个信息即可。

全部代码:

// Problem: 次小生成树
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/358/
// Memory Limit: 512 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#pragma GCC optimize("O3")
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
 
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define all(x) (x).begin(), (x).end()
 
#define x first
#define y second
using pii = pair<int, int>;
using ll = long long;
 
inline void read(int &x){
    int s=0; x=1;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

const int N=1e5+5, M=1e6+5, INF=1e9+10;

int n, m;

struct Msg{
	int u, v, w, vis;
}buf[M];

struct Edge{
	int to, w, next;
}e[M];

int h[N], tot;

void add(int u, int v, int w){
	e[tot].to=v, e[tot].w=w, e[tot].next=h[u], h[u]=tot++;
}

int f[N];

int find(int x){
	return x==f[x]? x: f[x]=find(f[x]);
}

ll MST(){
	ll res=0;
	rep(i,1,n) f[i]=i;
	rep(i,1,m){
		int u=buf[i].u, v=buf[i].v, w=buf[i].w;
		int pu=find(u), pv=find(v);
		if(pu!=pv) f[pu]=pv, res+=w, add(u, v, w), add(v, u, w), buf[i].vis=true;
	}
	return res;
}

int fa[N], son[N], sz[N], dep[N];
int W[N], val[N];
int top[N], dfn[N], ts;

void dfs1(int u, int f, int d){
	fa[u]=f, sz[u]=1, dep[u]=d;
	for(int i=h[u]; ~i; i=e[i].next){
		int go=e[i].to;
		if(go==f) continue;
		W[go]=e[i].w;
		dfs1(go, u, d+1);
		sz[u]+=sz[go];
		if(sz[son[u]]<sz[go]) son[u]=go;
	}
}

void dfs2(int u, int t){
	top[u]=t, dfn[u]=++ts, val[ts]=W[u];
	if(!son[u]) return;
	dfs2(son[u], t);
	for(int i=h[u]; ~i; i=e[i].next){
		int go=e[i].to;
		if(go==fa[u] || go==son[u]) continue;
		dfs2(go, go);
	}
}

struct Node{
	int l, r;
	int mx1, mx2;
	
	#define ls u<<1
	#define rs u<<1|1
}tr[N<<2];

Node merge(Node &L, Node &R){
	int rec[]={L.mx1, L.mx2, R.mx1, R.mx2};
	int mx1=-INF, mx2=-INF;
	for(auto i: rec) mx1=max(mx1, i); 
	rep(i,0,3) if(rec[i]!=mx1) mx2=max(mx2, rec[i]);
	return {L.l, R.r, mx1, mx2};
}

void build(int u, int l, int r){
	tr[u]={l, r};
	if(l==r) return tr[u].mx1=val[l], tr[u].mx2=-INF, void();
	int mid=l+r>>1;
	build(ls, l, mid), build(rs, mid+1, r);
	tr[u]=merge(tr[ls], tr[rs]);
}

void upd(int u, int x, int fir=-INF, int sec=-INF){
	if(tr[u].l==tr[u].r){
		tr[u].mx1=fir, tr[u].mx2=sec;
		return;
	}
	int mid=tr[u].l+tr[u].r>>1;
	if(x<=mid) upd(ls, x, fir, sec);
	else upd(rs, x, fir, sec);
	tr[u]=merge(tr[ls], tr[rs]);
}

Node query(int u, int l, int r){
	if(l<=tr[u].l && tr[u].r<=r) return tr[u];
	int mid=tr[u].l+tr[u].r>>1;
	Node L={-1}, R={-1};
	if(l<=mid) L=query(ls, l, r);
	if(mid<r) R=query(rs, l, r);
	if(L.l==-1) return R;
	if(R.l==-1) return L;
	return merge(L, R);
}

Node query(int u, int v){
	Node res={-1}, tmp;
	while(top[u]!=top[v]){
		int t=top[u];
		if(~res.l) res=merge((tmp=query(1, dfn[t], dfn[u])), res);
		else res=query(1, dfn[t], dfn[u]);
		u=fa[top[u]];
	}
	if(~res.l) res=merge((tmp=query(1, dfn[v], dfn[u])), res);
	else res=query(1, dfn[v], dfn[u]);
	return res;
}

int lca(int u, int v){
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]]) swap(u, v);
		u=fa[top[u]];
	}
	return dep[u]<dep[v]? u: v;
}

signed main(){
	memset(h, -1, sizeof h);	
	cin>>n>>m;
	rep(i,1,m){
		int u, v, w; read(u), read(v), read(w);
		buf[i]={u, v, w, 0};
	}
	
	sort(buf+1, buf+1+m, [&](const Msg &a, const Msg &b){
		return a.w<b.w;
	});
	
	ll res=MST();

	dfs1(1, -1, 1), dfs2(1, 1);
	build(1, 1, n);
	
	int del=INF;
	rep(i,1,m) if(!buf[i].vis){
		int u=buf[i].u, v=buf[i].v, w=buf[i].w;
		if(u==v) continue;
		int a=lca(u, v);
		Node L={-1}, R={-1}, res, rec;
		
		rec=query(a, a);
		upd(1, dfn[a]);
		if(a!=u) L=query(u, a);
		if(a!=v) R=query(v, a);
		upd(1, dfn[a], rec.mx1, rec.mx2);
		
		if(L.l==-1) res=R;
		else if(R.l==-1) res=L;
		else res=merge(L, R);
		
		if(w==res.mx1) del=min(del, w-res.mx2);
		else del=min(del, w-res.mx1);
	}
	cout<<res+del<<endl;
	
	return 0;
}

标签:ch,int,mx2,tr,生成,356,mx1,mx,AcWing
来源: https://www.cnblogs.com/Tenshi/p/16463956.html