【线段树】【最小生成树】BZOJ5216 [Lydsy2017省队十连测]公路建设

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/88015410

分析:

用线段树维护某个区间内的最优边(最多N条)

所以复杂度就是 O ( N l o g M Q + M l o g M ) O(N*logM*Q+MlogM)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 110
#define MAXM 100010
using namespace std;
struct node{
	int val,u,v;
	bool operator <(const node &a) const {
		return val<a.val;
	}
}e[MAXM];
int tmp[MAXN*2],sum[MAXN],tree[MAXM*4][MAXN];
int fa[MAXN];
int get_fa(int x){
	if(fa[x]==0)
		return x;
	fa[x]=get_fa(fa[x]);
	return fa[x];	
}
bool merge(int u,int v){
	u=get_fa(u);
	v=get_fa(v);
	if(u==v)
		return 0;
	fa[u]=v;
	return 1;	
}
bool sort_by_val(int a,int b){
	return e[a]<e[b];
}
void merge(int *res,int* a,int* b){
	tmp[0]=0;
	memset(fa,0,sizeof fa);
	for(int i=1,j=1;i<=a[0]||j<=b[0];){
		if(i<=a[0]&&(j>b[0]||e[a[i]]<e[b[j]])){
			tmp[++tmp[0]]=a[i];
			i++;
		}
		else{
			tmp[++tmp[0]]=b[j];
			j++;
		}
	}
	res[0]=0;	
	for(int i=1;i<=tmp[0];i++)
		if(merge(e[tmp[i]].u,e[tmp[i]].v))
			res[++res[0]]=tmp[i];
}
void build(int l,int r,int id){
	if(l==r){
		tree[id][0]=1;
		tree[id][1]=l;
		return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,id<<1);
	build(mid+1,r,id<<1|1);
	merge(tree[id],tree[id<<1],tree[id<<1|1]);
}
void query(int l,int r,int id,int l1,int r1){
	if(l>=l1&&r<=r1){
		merge(sum,sum,tree[id]);
		return ;
	}
	int mid=(l+r)>>1;
	if(l1<=mid)
		query(l,mid,id<<1,l1,r1);
	if(r1>mid)
		query(mid+1,r,id<<1|1,l1,r1);
}
int main(){
	int n,m,q,l,r;
	SF("%d%d%d",&n,&m,&q);
	for(int i=1;i<=m;i++)
		SF("%d%d%d",&e[i].u,&e[i].v,&e[i].val);
	build(1,m,1);
	for(int i=1;i<=q;i++){
		SF("%d%d",&l,&r);
		sum[0]=0;
		query(1,m,1,l,r);
		int ans=0;
		for(int i=1;i<=sum[0];i++)
			ans+=e[sum[i]].val;
		PF("%d\n",ans);
	}	
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/88015410