首页 > 其他分享 >【题解】Tree MST

【题解】Tree MST

时间:2023-04-15 09:13:59浏览次数:26  
标签:head int 题解 MST Tree son tail siz

题面

给定一棵 \(n\) 个节点的树,现有有一张完全图,两点 \(x,y\) 之间的边长为 \(w_x+w_y+dis_{x,y}\),其中 \(dis\) 表示树上两点的距离。

求完全图的最小生成树。

\(n \leq 2 \times 10^5\)。

题解

???神秘
借鉴支配对的思想,点分治后将树中点权替换为\(dep_i+w_i\),选择点权最小的一个和其他点连边,总共\(n\log n\)条边,跑最小生成树,总复杂度\(n \log^2 n\)。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(!isdigit(w)){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(isdigit(w)){
		j=j*10+w-'0';
		w=getchar();
	}
	return f*j;
}
const int N=200010;
int head[N],to[N*2],fro[N*2],len[N*2],tail;
int n,w[N],wk[N],dis[N],siz[N],son[N];
inline void adlin(int x,int y,int z){
	to[++tail]=y,fro[tail]=head[x],head[x]=tail,len[tail]=z;
	return ;
}
int Siz,Rt,Sum;
struct Lin{
	int u,v,len;
}link[N*40];
int cnt;
int lin[N],tot,p[N];
void getrt(int u,int fa){
	siz[u]=1;
	for(int k=head[u];k;k=fro[k]){
		int x=to[k];
		if(x==fa||wk[x])continue;
		getrt(x,u);
		siz[u]+=siz[x];
		son[u]=(siz[x]>siz[son[u]])?x:son[u];
	}
	int ma=max(siz[son[u]],Siz-siz[u]);
	if(ma<Sum)Sum=ma,Rt=u;
	return ;
}
void dfs(int u,int fa,int dep){
	siz[u]=1;
	p[u]=w[u]+dep;
	lin[++tot]=u;
	for(int k=head[u];k;k=fro[k]){
		int x=to[k];
		if(x==fa||wk[x])continue;
		dfs(x,u,dep+len[k]),siz[u]+=siz[x];
	}
	return ;
}
void init(int u,int v){
	Sum=1e18,Siz=v;
	getrt(u,0);
	int rt=Rt;
	tot=0,dfs(rt,0,0);
	sort(lin+1,lin+1+tot,[&](int a,int b){return p[a]<p[b];});
	for(int i=2;i<=tot;i++)link[++cnt]=(Lin){lin[1],lin[i],p[lin[1]]+p[lin[i]]};
	wk[rt]=true;
	for(int k=head[rt];k;k=fro[k]){
		int x=to[k];
		if(wk[x])continue;
		init(x,siz[x]);
	}
	return ;
}
int bel[N];
int getfa(int x){
	return (bel[x]==x)?x:bel[x]=getfa(bel[x]);
}
long long ans;
signed main(){
	n=rd();
	for(int i=1;i<=n;i++)w[i]=rd();
	for(int i=1;i<n;i++){
		int x=rd(),y=rd(),z=rd();
		adlin(x,y,z),adlin(y,x,z);
	}
	init(1,n);
	for(int i=1;i<=n;i++)bel[i]=i;
	sort(link+1,link+1+cnt,[&](Lin a,Lin b){return a.len<b.len;});
	for(int i=1;i<=cnt;i++){
		int u=link[i].u,v=link[i].v,k=link[i].len;
//		cout<<u<<"-"<<v<<":"<<w<<"\n";
		u=getfa(u),v=getfa(v);
		if(u!=v)bel[u]=v,ans+=k;
	}
	printf("%lld\n",ans);
	return 0;
}

标签:head,int,题解,MST,Tree,son,tail,siz
From: https://www.cnblogs.com/T-water/p/17320477.html

相关文章

  • [ABC296Ex] Unite 题解
    考虑状压dp。设\(f_{i,j,s}\)表示当前正在决策坐标为\((i,j)\)的格子,且列状态为\(s\)。其中列状态维护了当前轮廓线上的连通块,我们可以使用最小表示法来简单维护。(为什么不用广义括号序列?因为其涉及到\(5\)个可选值,由于\(m\le7\),所以这两个都需要用到八进制,而最小表示......
  • [Educational Codeforces Round 118 (Rated for Div. 2)]题解
    A题意:给定两个数,每一个数有两个属性,第一个属性是p1,第二个属性是p2.表示这个数有p2个后缀0.这个数本身等于p1后面加p2个0.问给你两个这种数,判断大小。思路:赛场上想到的:如果最终的长度不一样,可以直接根据长度判断。如果相等,就把后缀0加上直接比较大小就可以(比较字典序的大小),但......
  • 两个循环搞定多级菜单列表递归成tree
    菜单类publicstaticclassMenu{Menu(Stringdata){String[]split=data.split("");this.id=Integer.valueOf(split[0]);this.name=split[1];this.pid=Integer.valueOf(split[2]);......
  • 2012-2013 ACM-ICPC, NEERC, Moscow Subregional Contest题解
    题目链接:2012-2013ACM-ICPC,NEERC,MoscowSubregionalContestC.Cinderella(贪心)思路答案为大于平均值的数的数量代码#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;intmain(){ios::sync_with_stdio(false);cin.tie(nullptr);......
  • Codeforces Round #303 (Div. 2) E. Paths and Trees (最短路+变形最小生成树)
    题目地址:E.PathsandTrees模拟了一场CF,这场实在太水了。。边玩边做的。。最后半分钟交了一发E题。。不幸AK绝杀失败。。。。首先的思路肯定是先求最短路,把可能为最短路的边挑出来,然后第二步我本来写的是直接用无向图的最小生成树,于是绝杀失败。。。后来才发现这样是不行的。......
  • Codeforces Round #316 (Div. 2) D. Tree Requests (DFS序)
    题目地址:http://codeforces.com/contest/570/problem/D比赛的时候实在没想到DFS序,。。想到DFS序后,分别存起每个深度的所有节点的DFS序,处理出前缀异或和,然后二分找到两个端点,再异或一下,就求出了所求区间的异或和,由于偶数次的都被异或掉了,所以判断下奇数次数是否大于1即可。代码......
  • HDU 4812 D Tree (树上点分治)
    题目地址:HDU4812这题是13年南京区域赛的现场题。树分治思想。树分治的过程中记录下每个子树的所有到达根的路径的积,用best记录下每个积的最小端点,然后再枚举当前子树的每个积,然后用逆元的方法求出当积为k时所需要的另一个端点值,并更新答案。代码如下:#include<iostream>#......
  • SPOJ 375 QTREE系列-Query on a tree (树链剖分)
    题目地址:SPOJ375树链剖分第一发!果然是个貌似很高级的数据结构,其实就是把树的边从树形结构转化成了线性结构,从而可以用线段树或树状数组之类的数据结构进行快速维护。从而将时间缩到n*log(2*n).这题用的线段树维护的。代码如下:#include<iostream>#include<string.h......
  • POJ 3237 Tree (树链剖分)
    题目地址:POJ3237这题用了一下午。。本来一直认为max和min两个数组是不用改的,只需要改lazy数组,然后在查询的时候利用lazy标记来返回max或-min,后来发现错的很严重。。这题要在pushdown中修改max和min数组,从而实现最大值取反。代码如下:#include<iostream>#include<strin......
  • CF1473D 题解
    题目传送门题目分析线段树、前缀和、\(\text{ST}\)表题解都有了,我补一发猫树题解吧。由于每次操作只能将大小改变成跟原来差\(1\),所以只需要知道这段操作中的最大值和最小值,最后所求的答案的范围就被卡住了。对于每一次操作,我们把操作序列拦腰斩断,那么分别求两边的范围,最后减......