Kruskal重构树

【算法简介】

算法流程和Kruskal生成树类似,把边排序后,依据并查集加边即可,两个点认一个新的节点父亲,这个点的点权就是当前边权

所以我们最后得到了一个有2n-1个节点的带点权的树

	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=n*2;i++) fa[i]=i;
	cnt=n;
	for(int i=1;i<=m;i++)
	{
		int fx=find(e[i].u),fy=find(e[i].v);
		if(fx!=fy)
		{
			fa[fx]=fa[fy]=++cnt;
			ew[cnt]=e[i].val;
			add(cnt,fx); add(cnt,fy);
			in[fx]++; in[fy]++;
		}
	}

性质:

1、u,v经过的最大值,就是重构树上lca的值

如果从小到大加边,可以考虑越加边图的连通性越强,也就是说u->v的最大值,就是刚好加了某个点,使得u,v联通,这个点就是刚刚加入的u,v的lca

2、重构树中代表原树中的点的节点全是叶子节点,其余节点都代表了一条边的边权。

【例题】P4197 Peaks

【题意】

有点权也有边权的图中一点v开始走不超过x的边权,能够走到的所有节点的点权中第k大的值

【分析】

建出Kruskal重构树,问题就转化为了求子树中的第k大问题,就能想到主席树了

【代码】

#include
using namespace std;
const int maxn=2e5+5;
const int maxm=5e5+5;
const int inf=0x3f3f3f3f;
int n,m,q,root[maxn];
int h[maxn],in[maxn],fa[maxn];
struct edge
{
	int u,v,val;
}e[maxm];
bool cmp(edge a,edge b)
{
	return a.val>1;
	if(pos<=mid) update(tr[now].l,L,mid,pos,val);
	if(mid>1;
	if(sum>=k) return calc(tr[rx].r,tr[ry].r,mid+1,R,k);
	else return calc(tr[rx].l,tr[ry].l,L,mid,k-sum);
}
int query(int v,int x,int k)
{
	for(int i=18;i>=0;i--)  if(f[v][i] && ew[f[v][i]]<=x) v=f[v][i];
	if(siz[v]

 

你可能感兴趣的:(算法,Kruskal重构树)