bzoj5216 [Lydsy2017省队十连测]公路建设 (线段树)

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

Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 65 Solved: 36
[Submit][Status][Discuss]
## Description 在Byteland一共有n个城市,编号依次为1到n,它们之间计划修建m条双向道路,其中修建第i条道路的费用为ci。Byteasar作为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行,每行一个整数,即最小总费用。

用线段树维护每段区间最优解,每个节点记录所用边;
因为\(n\)只有\(100\),所以向上合并时暴力归并+并查集即可;
AC GET☆DAZE

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define N 139
#define mod 20070831
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
struct Seg_Tree
{
	int l,r,ans[102];
}tree[100039<<2];
struct edge
{
	int u,v,w;
}net[100039];
int n,m,q,fa[N],fu,fv,use,ans[N][N];
int find(int k)
{
	return fa[k]==k ? k : fa[k]=find(fa[k]);
}
void pull_up(int res[],int i[],int j[])
{
	int now=0,li=1,lj=1;
	for(int a=1;a<=n;a++) fa[a]=a;
	while(now<n && (i[li] || j[lj]))
	{
		while(now<n && i[li] && net[i[li]].w<=net[j[lj]].w)
		{
			fu=find(net[i[li]].u),fv=find(net[i[li]].v);
			if(fu!=fv) fa[fu]=fv,res[++now]=i[li];
			li++;
		}
		while(now<n && j[lj] && net[i[li]].w>=net[j[lj]].w)
		{
			fu=find(net[j[lj]].u),fv=find(net[j[lj]].v);
			if(fu!=fv) fa[fu]=fv,res[++now]=j[lj];
			lj++;
		}
	}
	while(now<n && res[now]) res[++now]=0;
}
void build(int k,int l,int r)
{
	tree[k].l=l,tree[k].r=r;
	if(l==r)
	{
		tree[k].ans[1]=r;
		return;
	}
	int mid=l+r>>1;
	build(k<<1,l,mid),build(k<<1|1,mid+1,r);
	pull_up(tree[k].ans,tree[k<<1].ans,tree[k<<1|1].ans);
}
void query(int k,int l,int r,int now)
{
	if(l<=tree[k].l && tree[k].r<=r)
	{
		for(int a=1;a<n;a++) ans[now][a]=tree[k].ans[a];
		return;
	}
	int mid=tree[k].l+tree[k].r>>1,ls=0,rs=0;
	if(mid>=r) query(k<<1,l,r,ls=++use);
	else if(mid<l) query(k<<1|1,l,r,rs=++use);
	else query(k<<1,l,mid,ls=++use),query(k<<1|1,mid+1,r,rs=++use);
	if(ls && !rs) for(int a=1;a<n;a++) ans[now][a]=ans[ls][a];
	if(!ls && rs) for(int a=1;a<n;a++) ans[now][a]=ans[rs][a];
	if(ls && rs) pull_up(ans[now],ans[ls],ans[rs]);
}
int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int a=1;a<=m;a++)
	{
		scanf("%d%d%d",&net[a].u,&net[a].v,&net[a].w);
	}
	net[0].w=inf;
	build(1,1,m);
	for(int a=1,b,c,d=0;a<=q;a++,d=0)
	{
		scanf("%d%d",&b,&c);
		query(1,b,c,use=1);
		for(int e=1;ans[1][e];e++)
		{
			d+=net[ans[1][e]].w;
		}
		printf("%d\n",d);
	}
	return 0;
}
posted @ 2018-04-09 11:31  Sinogi  阅读(465)  评论(1编辑  收藏  举报