bzoj 5216: [Lydsy2017省队十连测]公路建设

5216: [Lydsy2017省队十连测]公路建设

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 66  Solved: 37
[Submit][Status][Discuss]

Description

在Byteland一共有n个城市,编号依次为1到n,它们之间计划修建m条双向道路,其中修建第i条道路的费用为ci。B
yteasar作为Byteland公路建设项目的总工程师,他决定选定一个区间[l,r],仅使用编号在该区间内的道路。他希
望选择一些道路去修建,使得连通块的个数尽量少,同时,他不喜欢修建多余的道路,因此每个连通块都可以看成
一棵树的结构。为了选出最佳的区间, Byteasar会不断选择 q个区间,请写一个程序,帮助 Byteasar计算每个区
间内修建公路的最小总费用。 

Input

第一行包含三个正整数n; m; q,表示城市数、道路数和询问数。
接下来m 行,每行三个正整数ui; vi; ci,表示一条连接城市ui 和vi 的双向道路,费用为ci。
接下来q 行,每行两个正整数li; ri,表示一个询问。
1 ≤ ui, vi ≤ n, ui ̸= vi, 1 ≤ li ≤ ri ≤ m, 1 ≤ ci ≤ 10^6
N<=100,M<=100000,Q<=15000
 

Output

输出q 行,每行一个整数,即最小总费用。
 

Sample Input

3 5 2
1 3 2
2 3 1
2 1 6
3 1 7
2 3 7
2 5
3 4

Sample Output

7
13

HINT

 

Source

Claris原创,本站版权所有

    对边建线段树,对于线段树上一个节点对应的区间,我们记录下这个区间的边在原图中形成的最小生成森林的边是哪些。因为n<=100,所以最小生成森林最多只有99条边。然后我们合并的时候暴力一点,直接做一遍kruscal类似的东西,一次的复杂度是 O(N)。

    因为合并的时候可以直接归并,所以不用对边的权值排序,最后答案就是最小生成森林的边权和(这不是废话么2333)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=100005;
struct lines{
	int u,v,w;
}l[maxn];
int p[105],ans,n,m,Q,le,ri;
int ff(int x){ return p[x]==x?x:(p[x]=ff(p[x]));}
inline bool can(int x){
	int X=ff(l[x].u),Y=ff(l[x].v);
	if(X!=Y){
		p[X]=Y;
		return 1;
	}
	else return 0;
}
struct node{
	int L[105],num;
	node operator +(const node &x)const{
		node r;
		r.num=0;
		for(int i=1;i<=n;i++) p[i]=i;
		int j=1;
		for(int i=1;i<=num;i++){
			for(;j<=x.num&&l[x.L[j]].w<l[L[i]].w;j++)
				if(can(x.L[j])) r.L[++r.num]=x.L[j];
			if(can(L[i])) r.L[++r.num]=L[i];
		}
		for(;j<=x.num;j++) if(can(x.L[j])) r.L[++r.num]=x.L[j];
		
		return r;
	}
}a[maxn<<2|1],ANS;

void build(int o,int l,int r){
	if(l==r){
		a[o].L[a[o].num=1]=l;
		return;
	}
	int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1;
	build(lc,l,mid),build(rc,mid+1,r);
	a[o]=a[lc]+a[rc];
}

void query(int o,int l,int r){
	if(l>=le&&r<=ri){
	    ANS=ANS+a[o];
	    return;
	}
	int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1;
	if(le<=mid) query(lc,l,mid);
	if(ri>mid) query(rc,mid+1,r);
}

inline void prework(){
	for(int i=1;i<=m;i++) scanf("%d%d%d",&l[i].u,&l[i].v,&l[i].w);
	build(1,1,m);
}

inline void solve(){
	while(Q--){
		scanf("%d%d",&le,&ri);
		ANS.num=0;
		query(1,1,m),ans=0;
		for(int i=1;i<=ANS.num;i++) ans+=l[ANS.L[i]].w;
		printf("%d
",ans);
	}
}

int main(){
	scanf("%d%d%d",&n,&m,&Q);
	prework();
	solve();
	return 0;
}

  

原文地址:https://www.cnblogs.com/JYYHH/p/8762454.html