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

Posted Sinogi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\),所以向上合并时暴力归并+\(Kruskal\)即可;
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;
}

以上是关于bzoj5216 [Lydsy2017省队十连测]公路建设 (线段树)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj5219 [Lydsy2017省队十连测]最长路径 (DP)

BZOJ 5222[Lydsy2017省队十连测]怪题

Lydsy2017省队十连测

[Lydsy2017省队十连测]商店购物

[Lydsy2017省队十连测]最长路径

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