【YBTOJ】【Luogu P4180】[BJWC2010]严格次小生成树

【YBTOJ】【Luogu P4180】[BJWC2010]严格次小生成树:

链接:

洛谷

题目大意:

求次小生成树。

正文:

本题有一个至关重要的性质:次小生成树只与最小生成树有一边之差。

那么只用在最小生成树中加边,在环中的边里找一个最大的边减去。将所有这样的操作取最大,就是非严格最小生成树。有个“非”,是因为最大的边权可能与加边的边权相等,所以遇到这种情况要取次大值。

倍增操作求值就能解决问题了。

代码:

const int N = 1e5 + 10, M = 3e5 + 10;

inline ll Read()
{
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

// main
int n, m; 
int logN;
ll ans = 1e17, sum;

// edge
struct Edge
{
	struct edge
	{
		int from, to, nxt;ll val; bool t;
		bool operator < (edge &a) const
		{
			return val < a.val;
		}
	}e[M << 1];
	int head[N], tot;
	
	void add(int u, int v, ll w)
	{
		e[++tot] = (edge) {u, v, head[u], w, 1}, head[u] = tot;
	}
} g, t;

// Kruskal
int fa[N];
int Find(int k) {return k == fa[k]? k: fa[k] = Find(fa[k]);}
void Kruskal()
{
	sort (g.e + 1, g.e + 1 + m);
	for (int i = 1; i <= n; i++) fa[i] = i;
	for (int i = 1; i <= m; i++)
	{
		int u = Find(g.e[i].from), v = Find(g.e[i].to);
		if (u == v) continue;
		fa[u] = v;
		sum += g.e[i].val;
		t.add(g.e[i].from, g.e[i].to, g.e[i].val);
		t.add(g.e[i].to, g.e[i].from, g.e[i].val);
		g.e[i].t = 0;
	}
}

// LCA
int dep[N];
bool vis[N];
int f[N][30];
ll Max[N][30], sMax[N][30];

queue <int> q;
void BFS(int root)
{
	while(!q.empty()) q.pop();
	q.push(root);
	dep[root] = 1;
	while(!q.empty())
	{
		int u = q.front(); q.pop();
		vis[u] = 1;
		for (int i = t.head[u]; i; i = t.e[i].nxt)
		{
			int v = t.e[i].to;
			if (vis[v]) continue;
			dep[v] = dep[u] + 1;
			Max[v][0] = t.e[i].val;
			sMax[v][0] = -1e17;
			f[v][0] = u;
			for (int j = 1; j <= logN; j++)
			{
				f[v][j] = f[f[v][j - 1]][j - 1];
				sMax[v][j] = max(sMax[v][j - 1], sMax[f[v][j - 1]][j - 1]);
				Max[v][j] = max(Max[v][j - 1], Max[f[v][j - 1]][j - 1]);
				if (Max[v][j - 1] > Max[f[v][j - 1]][j - 1])
					sMax[v][j] = max(sMax[v][j], Max[f[v][j - 1]][j - 1]);
				if (Max[v][j - 1] < Max[f[v][j - 1]][j - 1])
					sMax[v][j] = max(sMax[v][j], Max[v][j - 1]);
			}
			q.push(v);
		}
	}
}

int LCA(int u, int v)
{
	if (dep[u] > dep[v]) u ^= v ^= u ^= v;
	for (int j = logN; ~j; j--)
		if(dep[f[v][j]] >= dep[u]) 
			v = f[v][j]; 
	if (u == v) return u;
	for (int j = logN; ~j; j--)
		if(f[v][j] != f[u][j])
			v = f[v][j], u = f[u][j];
	u = f[u][0], v = f[v][0];
	return u;
}

ll solve (int u, int v, ll k)
{
	ll ans = -1e17;
	for (int j = logN; ~j; j--)
		if(dep[f[u][j]] >= dep[v])
		{
			if (k != Max[u][j]) ans = max(ans, Max[u][j]);
			else ans = max(ans, sMax[u][j]);
			u = f[u][j];
		}
	return ans;
}

// main()
int main()
{
	n = Read(), m = Read();
	logN = log2(m) + 1;
	for (int i = 1; i <= m; i++) 
	{
		int u = Read(), v = Read(); ll w = Read();
		g.add(u, v, w);
	}
	
	Kruskal();
	BFS(1);
	
	for (int i = 1; i <= m; i++)
	{
		if (!g.e[i].t) continue;
		int u = g.e[i].from, v = g.e[i].to;
		ll tmp = sum, w = g.e[i].val;
		int c = LCA(u, v);
		tmp = tmp + w - max(solve (u, c, w), solve (v, c, w));
		ans = min(ans, tmp);
	}
	printf ("%lld\n", ans);
	return 0;
}
posted @ 2021-07-08 10:00  Jayun  阅读(42)  评论(0编辑  收藏  举报