zoukankan      html  css  js  c++  java
  • 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
    ",d);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Leetcode 15
    setjmp和longjmp重复使用的问题
    linux的下两种定时器实现
    linux中的信号处理
    【推荐软件】ack
    《代码大全》阅读心得二
    更换svn diff为vimdiff
    unpack的一点使用问题
    【lua】table是否为空的判断
    vi复制部分字符
  • 原文地址:https://www.cnblogs.com/Sinogi/p/8758652.html
Copyright © 2011-2022 走看看