码迷,mamicode.com
首页 > 其他好文 > 详细

floj 2264

时间:2020-01-11 23:56:23      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:题解   表示   opened   clear   family   hid   name   spl   uil   

2公路建设(highway.c/cpp/pas)

滨海一共有n 个城市,编号依次为1n,它们之间计划修建m条双向道路,其中修建第i条道路的费用为ci

海霸王作为滨海公路建设项目的总工程师,他决定选定一个区间[l,r],仅使用编号在该区间内的道路。他希望选择一些道路去修建,使得连通块的个数尽量少,同时,他不喜欢修建多余的道路,因此每个连通块都可以看成一棵树的结构。为了选出最佳的区间,海霸王会不断选择q个区间,请写一个程序,帮助海霸王计算每个区间内修建公路的最小总费用。

Input

第一行包含三个正整数n,m,q,表示城市数、道路数和询问数。接下来m行,每行三个正整数ui,vi,ci,表示一条连接城市uivi的双向道路,费用为ci接下来q行,每行两个正整数li,ri,表示一个询问。

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

Notes

60% 从ci=i。

100% 的数据,1 ui,vin<=100,uivi1lirim,1ci106

【题解】

考虑部分分,边的权值单调递增。

直接倒着扫所有边,加入该边时如果还未连通就直接加,否则找到环上最大的边删去换成这条,将查询按左端点从大到小排序,扫到左端点相同时查询现在树上所有边是否在区间内,是就将答案加它。

正解

发现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<<"\n";
    }
    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
View Code

floj 2264

标签:题解   表示   opened   clear   family   hid   name   spl   uil   

原文地址:https://www.cnblogs.com/betablewaloot/p/12181517.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!