bzoj 5216: [Lydsy2017省队十连测]公路建设
5216: [Lydsy2017省队十连测]公路建设
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 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
1 3 2
2 3 1
2 1 6
3 1 7
2 3 7
2 5
3 4
Sample Output
7
13
13
HINT
Source
对边建线段树,对于线段树上一个节点对应的区间,我们记录下这个区间的边在原图中形成的最小生成森林的边是哪些。因为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\n",ans); } } int main(){ scanf("%d%d%d",&n,&m,&Q); prework(); solve(); return 0; }
我爱学习,学习使我快乐