BZOI2010 次小生成树。

这是一道水题。。。。


题目要求的一幅图的严格次小生成树(就是说权值和要大于最小生成树,不能等于)


我们先来分析一下:


假设我们现在得到了最小生成树。


我们可以发现次小生成树肯定只是最小生成树修改一条边而已。。。这个很显然。


然后我们枚举非树边。


加入这条边之后我们会出现一个环(然后环切。)


我们要求两个东西,这个环(除了加进去的那条边之外)的最大权值和次大权值(严格意义)

可以发现的是,最大权值必定<=当前边的权值。


假如等于的话,我们就取代次大权值的边,否则,取代最大权值的边。

最后再更新一下答案就好了。


#include
  
  
   
   
#include
   
   
    
    
#include
    
    
     
     

using namespace std;

const int MAXN = 500005;

struct Node
{
	int son[2],fa,max,cmax;bool rev;
}T[MAXN];

struct Edge
{
	int u,v,cost;
}E[MAXN];

int Par[MAXN],Fa[MAXN],V[MAXN],N,M;
bool bz[MAXN];
pair
     
     
      
       H;

bool cmp(Edge a,Edge b) {return a.cost < b.cost;}

int get(int a) {return Fa[a] == a ? a : Fa[a] = get(Fa[a]);}

void Upd(int Nt,int l)
{
	if (T[l].max > T[Nt].max) T[Nt].cmax = max(T[Nt].max,T[l].cmax),T[Nt].max = T[l].max; else
		if (T[l].max < T[Nt].max) T[Nt].cmax = max(T[Nt].cmax,T[l].max);
}

void Update(int Nt)
{
	T[Nt].max = V[Nt],T[Nt].cmax = 0;
	int l = T[Nt].son[0],r = T[Nt].son[1];
	Upd(Nt,l),Upd(Nt,r);
}

void Label(int u)
{
	T[u].rev ^= 1,swap(T[u].son[0],T[u].son[1]);
}

void Lazy_down(int u)
{
	if (T[u].rev) Label(T[u].son[0]),Label(T[u].son[1]),T[u].rev = 0;
}

void Rotate(int u,int c)
{
	int fa = T[u].fa,ft = T[fa].fa;
	Lazy_down(u);
	T[fa].fa = u,T[u].fa = ft;
	if (ft) T[ft].son[T[ft].son[1] == fa] = u;
	T[fa].son[c] = T[u].son[!c];
	if (T[u].son[!c]) T[T[u].son[!c]].fa = fa;
	T[u].son[!c] = fa;
	Update(fa);
	if (Par[fa]) Par[u] = Par[fa],Par[fa] = 0;
}

void Splay(int u)
{
	for(Lazy_down(u);T[u].fa;)
	{
		int fa = T[u].fa,ft = T[fa].fa;
		Lazy_down(ft),Lazy_down(fa);
		if (!ft) Rotate(u,T[fa].son[1] == u); else
		{
			if (T[fa].son[1] == u)
			{
				if (T[ft].son[1] == fa) Rotate(fa,1),Rotate(u,1); else
					Rotate(u,1),Rotate(u,0);
			} else
				if (T[ft].son[0] == fa) Rotate(fa,0),Rotate(u,0); else
					Rotate(u,0),Rotate(u,1);
		}
	}
	Update(u);
}

int Access(int u,bool h)
{
	int nxt = 0;
	while (u)
	{
		Splay(u);
		if (h && !Par[u])
		{
			H = make_pair(T[nxt].max,T[nxt].cmax);
			int x = T[u].son[1];
			if (T[x].max > H.first) H.second = max(T[x].cmax,H.first),H.first = T[x].max; else
				if (T[x].max < H.first) H.second = max(H.second,T[x].max);
		}
		if (T[u].son[1]) T[T[u].son[1]].fa = 0,Par[T[u].son[1]] = u;
		T[u].son[1] = nxt;if (nxt) T[nxt].fa = u;Par[nxt] = 0;
		Update(u);
		nxt = u,u = Par[u];
	}
	return nxt;
}

void Evert(int u)
{
	Label(Access(u,0));
}

void link(int u,int v)
{
	Evert(u),Evert(v),Splay(v),Par[v] = u,Access(v,0);
}

int main()
{
	scanf("%d %d", &N, &M);
	for(int i = 1;i <= M;i ++) scanf("%d %d %d", &E[i].u, &E[i].v, &E[i].cost);
	for(int i = 1;i <= N;i ++) Fa[i] = i;
	sort(E + 1,E + M + 1,cmp);
	long long Total = 0;
	for(int i = 1;i <= M;i ++)
		if (get(E[i].u) != get(E[i].v))
		{
			Fa[get(E[i].u)] = get(E[i].v);
			bz[i] = 1;
			Total += E[i].cost;
			V[i + N] = E[i].cost,link(E[i].u,i + N),link(i + N,E[i].v);
		}
	long long Ans = 1LL << 61;
	for(int i = 1;i <= M;i ++) if (!bz[i])
	{
		Access(E[i].u,0),Access(E[i].v,1);
		if (H.first == E[i].cost) Ans = min(Ans,(long long)E[i].cost - H.second); else
			if (H.first != E[i].cost) Ans = min(Ans,(long long)E[i].cost - H.first);
	}
	printf("%I64d\n",Total + Ans);
}

     
     
    
    
   
   
  
  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值