zoukankan      html  css  js  c++  java
  • [NOIP2013提高组]货车运输

    题目:洛谷P1967、Vijos P1843、codevs3287。

    题目大意:有n个城市m条道路,每条道路有一个限重,规定货车运货不能超过限重。有一些询问,问你两个城市之间一次最多能运多少重的货(可能无法到达)。

    解题思路:首先,要保证原来连通的点连通,限重要尽可能大,所以最大生成树。然后对每个询问找两个点的最近公共祖先,然后求出两点路径上最大限重的最小值即可。

    用倍增求LCA,可以边算边求出最小值,不用用一些复杂的方法。代码中我用sml[x][i]表示x和它的第$2^i$个祖先之间的路径上最大限重的最小值。然后在倍增时更新答案即可。详见代码

    C++ Code:

    #include<cstdio>
    #include<algorithm>
    #include<cctype>
    #include<cstring>
    #include<cstdio>
    using std::sort;
    using std::swap;
    struct edge{
    	int u,v,t;
    	bool operator < (const edge& rhs)const{return t>rhs.t;}
    }e[50005];
    struct tree_edge{
    	int to,dist,nxt;
    }E[120005];
    int n,m,fa[10005],head[10005]={0},cnt=0,ans,deep[10005],p[10005][16],sml[10005][16];
    inline int min(int a,int b){return(a<b)?(a):(b);}
    inline int readint(){
    	char c=getchar();
    	int p=0;
    	for(;!isdigit(c);c=getchar());
    	for(;isdigit(c);c=getchar())p=(p<<3)+(p<<1)+(c^'0');
    	return p;
    }
    int dad(int x){return(fa[x]==x)?(x):(fa[x]=dad(fa[x]));}
    inline int addedge(int from,int to,int dist){
    	E[++cnt]=(tree_edge){to,dist,head[from]};
    	head[from]=cnt;
    	E[++cnt]=(tree_edge){from,dist,head[to]};
    	head[to]=cnt;
    }
    void dfs(int u){
    	for(int i=head[u];i;i=E[i].nxt)
    	if(!deep[E[i].to]){
    		deep[E[i].to]=deep[u]+1;
    		p[E[i].to][0]=u;
    		sml[E[i].to][0]=E[i].dist;
    		dfs(E[i].to);
    	}
    }
    void init(){
    	for(int j=1;(1<<j)<=n;++j)
    	for(int i=1;i<=n;++i)
    	if(p[i][j-1]!=-1)
    	p[i][j]=p[p[i][j-1]][j-1],sml[i][j]=min(sml[i][j-1],sml[p[i][j-1]][j-1]);
    }
    int lca(int x,int y,int& ans){
    	ans=2000000000;
    	int i;
    	if(deep[x]<deep[y])swap(x,y);
    	for(i=0;(1<<i)<=n;++i);--i;
    	for(int j=i;j>=0;--j)
    	if(deep[p[x][j]]>=deep[y]){
    		ans=min(ans,sml[x][j]),x=p[x][j];
    	}
    	if(x==y)return x;
    	for(int j=i;j>=0;--j)
    	if(p[x][j]!=p[y][j]&&p[x][j]!=-1){
    		ans=min(ans,min(sml[x][j],sml[y][j]));
    		x=p[x][j];
    		y=p[y][j];
    	}
    	ans=min(ans,min(sml[x][0],sml[y][0]));
    	return p[x][0];
    }
    int main(){
    	n=readint(),m=readint();
    	for(int i=1;i<=m;++i)e[i].u=readint(),e[i].v=readint(),e[i].t=readint();
    	sort(e+1,e+m+1);
    	for(int i=1;i<=n;++i)fa[i]=i;
    	for(int okE=1,now=1;now<=m;++now){
    		int a=dad(e[now].u),b=dad(e[now].v);
    		if(a!=b){
    			fa[b]=a;
    			addedge(e[now].u,e[now].v,e[now].t);
    			++okE;
    		}
    		if(okE==n)break;
    	}
    	int Q=readint();
    	memset(deep,0,sizeof deep);
    	memset(p,-1,sizeof p);
    	memset(sml,0x3f,sizeof sml);
    	for(int i=1;i<=n;++i)
    	if(!deep[i]){
    		deep[i]=1;
    		dfs(i);
    	}
    	init();
    	while(Q--){
    		int x=readint(),y=readint();
    		int a=dad(x),b=dad(y);
    		if(a!=b){
    			puts("-1");
    			continue;
    		}
    		lca(x,y,ans);
    		printf("%d
    ",ans);
    	}
    }
    
  • 相关阅读:
    C# WinForm下,隐藏主窗体,只在进程管理器中显示进程,在任务栏,状态栏都不显示窗体的方法
    C#全能数据库操作类及调用示例
    多个汇总列转换为行记录 mssql
    Oracle 10g创建数据库 用户等基本操作
    Jquery基本选择器 层次选择器 过滤选择器 表单选择器使用示例 带注释
    SQL与ORACLE的外键约束级联更新和删除
    C# 屏幕监控 自动截屏程序 主窗体隐藏,仅在进程中显示
    图文讲解VS2010程序打包操作 安装卸载
    查表法按日期生成流水号 mssql
    给DataTable添加主键 几何级提升Select筛选数据的速度
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/7553858.html
Copyright © 2011-2022 走看看