1. 程式人生 > >luogu4234 最小差值生成樹

luogu4234 最小差值生成樹

true 當前 main != 解法 最大 tree operator ring

題目大意

  在一個帶權無向圖中,它的最小差值生成樹為最大邊與最小邊差值最小的生成樹。求一個圖的最小差值生成樹。

題解

30分解法

  引理1 最小生成樹的最大邊的邊權是所有生成樹中最大邊邊權中的最小值。
  證明:任意一棵生成樹都可以在最小生成樹的基礎上,通過不斷取一個樹外邊e,將其替換掉其與生成樹所在環中的一條邊的方式而得到。我們就看看第一條用來替換的邊的情況吧。在不在最小生成樹中的邊中任取一個邊權小於最小生成樹最大邊m的邊e,則e必然與最小生成樹的樹邊形成環。若m不在環中,那麽就是替換掉任意一條邊,答案也沒有影響。如果m在環中,且用e替換掉m可以得到一個最大邊權更小的生成樹,那麽原來的最小生成樹就不是最小生成樹了。因此原命題成立。

  因此,我們可以將邊排序,不斷將最小邊刪除並求一遍Kruskal,最終取min即可。

100分解法

  拆邊,用LCT。先將最小生成樹加入LCT中,然後從小到達枚舉每一條樹外邊,將其和樹邊所在環中最小邊刪除然後納入LCT中,每次在外部更新最大值與最小值的差的最小值即可。

解法正確性證明

  證明目標 若答案生成樹的最小邊權和最大邊權為L‘, R‘,則當我們按照此方法枚舉到R‘時,L‘就是當前生成樹中的最小邊權。

  假設在經過R‘之前,中間狀態生成樹的最小邊權為L(L < L‘),最大邊權為R。

  引理2 邊權位於[L, R‘]內的邊集中必然存在一條邊e,使得e和邊權為L的邊位於一個環內,且L為最小邊權。
  證明:假設命題不成立,如果要使答案為L‘,邊權L的邊必須去除。如果[L, R‘]內沒有滿足條件的e,則e的邊權>R‘,這與R‘的定義矛盾。

  引理3 在中間狀態下,若邊權為L‘的邊在生成樹內,則邊權位於[L, R‘]內的邊集中必然不存在一條邊e,e和邊權為L‘的邊在一個環內,且L‘是環中的最小邊權。
  證明:假設命題不成立,L‘不在生成樹內,答案就不可能是[L‘, R‘]。

  引理4 在中間狀態下,若邊權為L‘的邊不在生成樹內,則在[L, L‘]中必然存在一條邊e,使得邊權為L‘的邊和e在一個環內,且L‘不是環中的最小邊。
  證明:假設命題不成立,那麽在L‘所在環中選其它一條邊,邊權為L‘‘,則L‘‘, R是一個更優的答案,產生了矛盾。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
using namespace std;

const int MAX_NODE = 50010, MAX_EDGE = 200010, INF = 0x3f3f3f3f;
int TotNode, TotEdge, Ans;

struct Edge
{
	int From, To, Weight;
	bool InTree;

	bool operator < (const Edge& a) const
	{
		return Weight < a.Weight;
	}
}_edges[MAX_EDGE];
int MaxEdgeP, MinEdgeP;

struct LCT
{
private:
	static const int MAX_TREE_NODE = MAX_NODE + MAX_EDGE;

	struct Node
	{
		int Val, Id;
		bool Rev;
		Node *Father, *LeftSon, *RightSon, *MinValP;

		bool IsRoot()
		{
			return !Father || (Father->LeftSon != this && Father->RightSon != this);
		}

		bool IsLeftSon()
		{
			return Father->LeftSon == this;
		}

		void Refresh()
		{
			MinValP = this;
			if (LeftSon && LeftSon->MinValP->Val < MinValP->Val)
				MinValP = LeftSon->MinValP;
			if (RightSon && RightSon->MinValP->Val < MinValP->Val)
				MinValP = RightSon->MinValP;
		}

		void Reverse()
		{
			swap(LeftSon, RightSon);
			Rev = !Rev;
		}

		void PushDown()
		{
			if (Rev)
			{
				if (LeftSon)
					LeftSon->Reverse();
				if (RightSon)
					RightSon->Reverse();
				Rev = false;
			}
		}
	}_nodes[MAX_TREE_NODE];

	struct SplayTree
	{
	private:
		Node *InnerRoot;

		void PushDown(Node *cur)
		{
			if (!cur->IsRoot())
			{
				PushDown(cur->Father);
			}
			cur->PushDown();
		}

		void Rotate(Node *cur)
		{
			Node *gfa = cur->Father->Father;
			Node **gfaSon = cur->Father->IsRoot() ? &InnerRoot : cur->Father->IsLeftSon() ? &gfa->LeftSon : &gfa->RightSon;
			Node **faSon = cur->IsLeftSon() ? &cur->Father->LeftSon : &cur->Father->RightSon;
			Node **curSon = cur->IsLeftSon() ? &cur->RightSon : &cur->LeftSon;
			*faSon = *curSon;
			if (*faSon)
				(*faSon)->Father = cur->Father;
			*curSon = cur->Father;
			(*curSon)->Father = cur;
			*gfaSon = cur;
			(*gfaSon)->Father = gfa;
			(*curSon)->Refresh();
			cur->Refresh();
		}

	public:
		void Splay(Node *cur)
		{
			PushDown(cur);
			while (!cur->IsRoot())
			{
				if (!cur->Father->IsRoot())
					Rotate(cur->Father->IsLeftSon() == cur->IsLeftSon() ? cur->Father : cur);
				Rotate(cur);
			}
		}
	}t;

	void Access(Node *cur)
	{
		Node *prev = NULL;
		while (cur)
		{
			t.Splay(cur);
			cur->RightSon = prev;
			cur->Refresh();
			prev = cur;
			cur = cur->Father;
		}
	}

	void MakeRoot(Node *cur)
	{
		Access(cur);
		t.Splay(cur);
		cur->Reverse();
	}

	void MakePath(Node *u, Node *v)
	{
		MakeRoot(v);
		Access(u);
		t.Splay(u);
	}

	void Link(Node *u, Node *v)
	{
		MakeRoot(v);
		v->Father = u;
	}

	void Cut(Node *u, Node *v)
	{
		MakePath(u, v);
		assert(v->Father == u);
		assert(u->LeftSon == v);
		u->LeftSon = NULL;
		v->Father = NULL;
		u->Refresh();
	}

	Node *FindRoot(Node *cur)
	{
		while (cur->Father)
			cur = cur->Father;
		while (cur->LeftSon)
			cur = cur->LeftSon;
		return cur;
	}

	Node *GetMinNode(Node *u, Node *v)
	{
		if (FindRoot(u) != FindRoot(v))
			return NULL;
		MakePath(u, v);
		return u->MinValP;
	}

public:
	LCT()
	{
		for (int i = 1; i <= 100; i++)
			_nodes[i].Id = i;
	}

	void SetNode(int v, int val)
	{
		_nodes[v].Val = val;
	}

	void Link(int u, int v)
	{
		Link(_nodes + u, _nodes + v);
	}

	void Cut(int u, int v)
	{
		Cut(_nodes + u, _nodes + v);
	}

	int GetMinId(int u, int v)
	{
		Node *ans = GetMinNode(_nodes + u, _nodes + v);
		if (ans == NULL)
			return -1;
		else
			return ans - _nodes;
	}
}g;

void InitBuild()
{
	sort(_edges + 1, _edges + TotEdge + 1);
	for (int i = 1; i <= TotEdge; i++)
		g.SetNode(TotNode + i, _edges[i].Weight);
	for (int i = 1; i <= TotNode; i++)
		g.SetNode(i, INF);
	int cnt = 0, curEdge = 0;
	while (cnt < TotNode - 1)
	{
		curEdge++;
		int k = g.GetMinId(_edges[curEdge].From, _edges[curEdge].To);
		if (k == -1)
		{
			cnt++;
			g.Link(_edges[curEdge].To, curEdge + TotNode);
			g.Link(curEdge + TotNode, _edges[curEdge].From);
			_edges[curEdge].InTree = true;
			MaxEdgeP = curEdge;
		}
	}
	Ans = _edges[MaxEdgeP].Weight - _edges[1].Weight;
	MinEdgeP = 1;
}

int GetAns()
{
	for (int i = 1; i <= TotEdge; i++)
	{
		if (_edges[i].InTree)
			continue;

		_edges[i].InTree = true;
		if (_edges[i].Weight > _edges[MaxEdgeP].Weight)
			MaxEdgeP = i;

		int cutEdge = g.GetMinId(_edges[i].From, _edges[i].To);
		assert(cutEdge != -1);
		g.Cut(_edges[cutEdge - TotNode].To, cutEdge);
		g.Cut(cutEdge, _edges[cutEdge - TotNode].From);
		_edges[cutEdge - TotNode].InTree = false;
		if (MaxEdgeP == cutEdge - TotNode)
			while (!_edges[MaxEdgeP].InTree)
				MaxEdgeP--;
		if (MinEdgeP == cutEdge - TotNode)
			while (!_edges[MinEdgeP].InTree)
				MinEdgeP++;

		Ans = min(Ans, _edges[MaxEdgeP].Weight - _edges[MinEdgeP].Weight);
		g.Link(_edges[i].To, i + TotNode);
		g.Link(i + TotNode, _edges[i].From);
	}
	return Ans;
}


int main()
{
	scanf("%d%d", &TotNode, &TotEdge);
	for (int i = 1; i <= TotEdge; i++)
	{
		scanf("%d%d%d", &_edges[i].From, &_edges[i].To, &_edges[i].Weight);
		while (_edges[i].From == _edges[i].To)
		{
			TotEdge--;
			scanf("%d%d%d", &_edges[i].From, &_edges[i].To, &_edges[i].Weight);
		}
	}
	InitBuild();
	printf("%d\n", GetAns());
	return 0;
}

  

luogu4234 最小差值生成樹