2、公路建设(highway.c/cpp/pas)
在滨海市一共有n 个城市,编号依次为1到n,它们之间计划修建m条双向道路,其中修建第i条道路的费用为ci。
海霸王作为滨海市公路建设项目的总工程师,他决定选定一个区间[l,r],仅使用编号在该区间内的道路。他希望选择一些道路去修建,使得连通块的个数尽量少,同时,他不喜欢修建多余的道路,因此每个连通块都可以看成一棵树的结构。为了选出最佳的区间,海霸王会不断选择q个区间,请写一个程序,帮助海霸王计算每个区间内修建公路的最小总费用。
Input
第一行包含三个正整数n,m,q,表示城市数、道路数和询问数。接下来m行,每行三个正整数ui,vi,ci,表示一条连接城市ui和vi的双向道路,费用为ci。接下来q行,每行两个正整数li,ri,表示一个询问。
Output输出q行,每行一个整数,即最小总费用。
Notes
60% 从ci=i。
100% 的数据,1 ≤ui,vi≤n<=100,ui≠vi,1≤li≤ri≤m,1≤ci≤106。
【题解】
考虑部分分,边的权值单调递增。
直接倒着扫所有边,加入该边时如果还未连通就直接加,否则找到环上最大的边删去换成这条,将查询按左端点从大到小排序,扫到左端点相同时查询现在树上所有边是否在区间内,是就将答案加它。
正解
发现n很小,可以使用线段树,叶子结点表示每条路,区间查询[l,r]即可。
每个节点维护一个vector表示这个区间内生成的最小生成森林选了那些边。
合并时使用归并排序,将2个区间的边排序后跑克鲁斯卡尔即可。
复杂度m*n+q*logm*n。
代码如下:
#include<bits/stdc++.h> using namespace std; const int M=1e5+5; int n,m,q,fa[105],b[M]; struct bian { int u,v,c,id; }a[M]; vector <int> ve[M<<2],ddhu,ans; inline int find(int x) { if(x==fa[x]) return x; fa[x]=find(fa[x]); return fa[x]; } inline int read() { char c=getchar(); int x=0,f=1; while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();} while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();} return x*f; } inline void pushup(int x,int y) { ddhu.clear(); int cnt=0,zi=0,yi=0,zlen=ve[x].size(),ylen=ve[y].size(); while(zi<zlen&&yi<ylen) { if(a[ve[x][zi]].c<a[ve[y][yi]].c) b[++cnt]=ve[x][zi++]; else b[++cnt]=ve[y][yi++]; } while(zi<zlen) b[++cnt]=ve[x][zi++]; while(yi<ylen) b[++cnt]=ve[y][yi++]; for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=cnt;i++) { int fa1=find(a[b[i]].u); int fa2=find(a[b[i]].v); if(fa1!=fa2) { fa[fa1]=fa2; ddhu.push_back(b[i]); } } } inline void build(int now,int l,int r) { if(l==r) { ve[now].push_back(l); return; } int mid=(l+r)>>1; build(now<<1,l,mid); build(now<<1|1,mid+1,r); pushup(now<<1,now<<1|1); ve[now].clear(); int gu=ddhu.size(); for(int i=0;i<gu;i++) ve[now].push_back(ddhu[i]); } inline void query(int now,int l,int r,int L,int R) { if(l>=L&&r<=R) { int huan=ans.size(); ve[(M<<2)-2].clear(); for(int i=0;i<huan;i++) ve[(M<<2)-2].push_back(ans[i]); pushup((M<<2)-2,now);huan=ddhu.size();ans.clear(); for(int i=0;i<huan;i++) ans.push_back(ddhu[i]); return; } int mid=(l+r)>>1; if(L<=mid) query(now<<1,l,mid,L,R); if(R>=mid+1) query(now<<1|1,mid+1,r,L,R); } int main() { // freopen("highway.in","r",stdin); // freopen("highway.out","w",stdout); n=read();m=read();q=read(); for(int i=1;i<=m;i++) a[i].u=read(),a[i].v=read(),a[i].c=read(); build(1,1,m); for(int i=1,x,y;i<=q;i++) { x=read();y=read(); ans.clear(); query(1,1,m,x,y); int daan=0,huan=ans.size(); for(int j=0;j<huan;j++) daan+=a[ans[j]].c; cout<<daan<<" "; } fclose(stdin); fclose(stdout); } //3 5 2 //1 3 2 //2 3 1 //2 1 6 //3 1 7 //2 3 7 //2 5 //3 4