首页 > 其他分享 >【XSY3810】公路建设(线段树,kruskal)

【XSY3810】公路建设(线段树,kruskal)

时间:2022-10-30 12:59:48浏览次数:61  
标签:return int kruskal sum 区间 XSY3810 线段 size

题面

在这里插入图片描述

题解

一开始竟然没反应过来是最小生成树。

考虑用线段树直接维护每个区间的答案。

注意到一个区间最多只有 \(n-1\) 条树边有用,所以线段树每个节点用一个 vector按权值从小到大保存区间内用到的树边即可。

合并两个区间的信息时,只需要将两棵子树存的树边归并排序,然后做 Kruskal 算法。

时间复杂度 \(O\big((m+q\log m)n\alpha(n)\big)\)。

#include<bits/stdc++.h>

#define N 110
#define M 100010

using namespace std;

struct edge
{
	int u,v,w;
}e[M];

struct data
{
	int sum;
	vector<edge>v;
	data()
	{
		sum=0;
		v.clear();
	}
}t[M<<2];

int n,m,q,fa[N];

vector<edge>tmp;

void Sort(vector<edge>a,vector<edge>b)
{
	tmp.clear();
	int cnta=0,cntb=0,size1=a.size(),size2=b.size();
	while(cnta<size1&&cntb<size2)
	{
		if(a[cnta].w<b[cntb].w)
		{
			tmp.push_back(a[cnta]);
			cnta++;
		}
		else
		{
			tmp.push_back(b[cntb]);
			cntb++;
		}
	}
	while(cnta<size1)
	{
		tmp.push_back(a[cnta]);
		cnta++;
	}
	while(cntb<size2)
	{
		tmp.push_back(b[cntb]);
		cntb++;
	}
}

int find(int x)
{
	return x==fa[x]?x:(fa[x]=find(fa[x]));
}

data Kruskal()
{
	data ans;
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=0,size=tmp.size(),tot=0;i<size&&tot<n-1;i++)
	{
		int a=find(tmp[i].u),b=find(tmp[i].v);
		if(a!=b)
		{
			fa[a]=b;
			tot++;
			ans.v.push_back(tmp[i]);
			ans.sum+=tmp[i].w;
		}
	}
	return ans;
}

void build(int k,int l,int r)
{
	if(l==r)
	{
		if(n>1)
		{
			t[k].v.push_back(e[l]);
			t[k].sum=e[l].w;
		}
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	Sort(t[k<<1].v,t[k<<1|1].v);
	t[k]=Kruskal();
//	printf("l=%d r=%d edge=",l,r);
//	for(int i=0,size=t[k].v.size();i<size;i++)
//		printf("(%d,%d,%d) ",t[k].v[i].u,t[k].v[i].v,t[k].v[i].w);
//	printf("sum=%d\n",t[k].sum);
}

data query(int k,int l,int r,int ql,int qr)
{
	if(ql<=l&&r<=qr) return t[k];
	int mid=(l+r)>>1;
	if(qr<=mid) return query(k<<1,l,mid,ql,qr);
	if(ql>mid) return query(k<<1|1,mid+1,r,ql,qr);
	Sort(query(k<<1,l,mid,ql,qr).v,query(k<<1|1,mid+1,r,ql,qr).v);
	return Kruskal();
}

int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=m;i++)
		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
	build(1,1,m);
	while(q--)
	{
		int l,r;
		scanf("%d%d",&l,&r);
		printf("%d\n",query(1,1,m,l,r).sum);
	}
	return 0;
}
/*
3 5 2
1 3 2
2 3 1
2 1 6
3 1 7
2 3 7
2 5
3 4
*/

标签:return,int,kruskal,sum,区间,XSY3810,线段,size
From: https://www.cnblogs.com/ez-lcw/p/16841028.html

相关文章

  • 【XSY3551】Inserting Lines(线段树)
    题意:数轴上有无穷个格子,每个坐标上各有一个格子,你需要支持以下操作共\(n\)次:在\(x=k\)这个格子前插入一个格子,并将所有\(x\geqk\)的格子后移一位。时间++。询问......
  • 【XSY3549】Tree(线段树,换根)
    原题不想说(太懒了),就说一下总结到的两点想法?对于树上多次询问路径信息的问题,如果两条路径的信息无法快速合并(即不能pushup),但是在路径两端增加/删除单点后的信息变化可以......
  • 基本线段树
    线段树P3372【模板】线段树1已知一个数列ai,有下列两种操作将区间[x,y]内每个数加上k求区间[x,y]中每个数的和线段树的思想便是将数列a,用若干个区间,在树上用结点表......
  • 【XSY3490】线段树(广义线段树,树上莫队)
    题面线段树题解本题分两Part走。Part1我们需要解决:如何在广义线段树上快速区间定位节点。对于有\(n\)个叶子节点、共\(2n-1\)个节点的广义线段树\(A\),我们......
  • 【XSY3434】【UOJ431】time map(线段树维护位运算)
    首先注意到一个性质:如果我们把权值相同且相邻的点归为一个连通块的话,那么一个叶子节点往上会经过至多\(O(\logV)\)个连通块(因为父亲节点一定是儿子节点的子集)。又注意......
  • 【XSY3326】米缸(时间复杂度均衡,线段树,基环树,倍增)
    时间复杂度的均衡。先考虑暴力的想法:显然这是一棵基环树,那么我们每次修改时暴力\(O(nm)\)重构基环树,然后询问的时候就能\(O(1)\)查询。时间复杂度\(O(nmq)\)。考虑......
  • 【XSY3367】青春野狼不做姐控偶像的梦(线段树)
    题意:给一个\(1\simn\)的排列,多次询问某段区间内的值域连续子区间的个数。区间值域连续的另一种表达方式:\(max-min=r-l\),即\((max-min)-(r-l)=0\)。考虑\(l=1,r=n\)......
  • CG2017 PA1-2 Crossroad (十字路口) 暴力求解2 线段、射线、直线、圆两两相交的简单
    题目是上一个随笔的题目,这次只判断交点个数不求出具体坐标,还是72.5分,看来卡O(n^2)复杂度卡得死死的。这次的代码给出了简单的线段、射线、直线、圆两两相交的判断交点个数......
  • 【THUWC2020】Day2T2(dfs树,DP,线段树合并)
    对于每一个点\(u\),我们先找到满足右述条件的深度最小的\(u\)祖先\(f\)并记这个深度最小的祖先的深度为\(dp(u)\):\(f\)能只通过除了树上\([f,u]\)路径所包含的边之......
  • 【P4314】CPU监控(线段树维护区间历史信息)
    线段树维护区间历史信息的模板题。看了cmd的博客。大概思路是:由于我们需要求出历史信息,所以暴力的做法是在做区间修改时的tag我们先不合并,而是按时间顺序存一个tag......