首页 > 代码库 > 【CODEVS 3287】【NOIP2013】火车运输

【CODEVS 3287】【NOIP2013】火车运输

http://codevs.cn/problem/3287/

题目描述

技术分享 国有 技术分享 座城市,编号从 技术分享技术分享,城市之间有 技术分享 条双向道路。每一条道路对车辆都有重
量限制,简称限重。现在有 技术分享 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的
情况下,最多能运多重的货物。

输入格式

输入文件第一行有两个用一个空格隔开的整数 技术分享, 表示 技术分享 国有 技术分享 座城市和 技术分享 条道
路。
接下来 技术分享 行每行 技术分享 个整数 技术分享,每两个整数之间用一个空格隔开,表示从 技术分享 号城市
技术分享 号城市有一条限重为 技术分享 的道路。注意: 技术分享 不等于 技术分享,两座城市之间可能有多条道路。
接下来一行有一个整数 技术分享,表示有 技术分享 辆货车需要运货。
接下来 技术分享 行,每行两个整数 技术分享技术分享,之间用一个空格隔开,表示一辆货车需要从 技术分享 城市
运输货物到 技术分享城市,注意:技术分享 不等于 技术分享

输出格式

输出共有 技术分享 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货
车不能到达目的地,输出 技术分享

输入样例

4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3

输出样例

3
-1
3

数据范围

技术分享

 

题解

可以证明最优路径一定在最大生成树(森林)上,于是题目便转化为,询问森林中两点路径上边权最小值,连通性用并查集判断即可。

对于一棵树上的一次询问,可以用倍增的方法解决。

技术分享 表示点 技术分享 向上 技术分享 步到达的结点                            技术分享

技术分享 表示点 技术分享 向上 技术分享 步的路径中的边权最小值 技术分享

 

 

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#define N 10005
#define M 50005
#define depth 21
using namespace std;

int n,m,q,cnt,tot,ans;
int f[N],last[N],dep[N];
int anc[N][22],g[N][22];
struct hh
{int to,next,w;}e[M<<1];
struct hhh
{int l,r,w;}line[M<<1];
bool cmp(hhh a,hhh b){return a.w>b.w;}
int read()
{
    int ret=0;char c=getchar();
    while(!isdigit(c))c=getchar();
    while(isdigit(c)){ret=(ret<<1)+(ret<<3)+c-0;c=getchar();}
    return ret;
}
void add(int a,int b,int w)
{
    e[++tot].to=b;
    e[tot].next=last[a];
    e[tot].w=w;
    last[a]=tot;
}
void bfs(int root)
{
    int i,j,now;
    stack<int> s;
    s.push(root);dep[root]=1;
    for(i=0;i<depth;i++) anc[root][i]=root;
    while(!s.empty())
    {
        now=s.top();s.pop();    
        if(now!=root)
            for(i=1;i<depth;i++)
            {
                anc[now][i]=anc[anc[now][i-1]][i-1];
                g[now][i]=min(g[now][i-1],g[anc[now][i-1]][i-1]);
            }                
        for(i=last[now];i;i=e[i].next)
            if(!dep[e[i].to])
            {
                anc[e[i].to][0]=now;
                dep[e[i].to]=dep[now]+1;
                g[e[i].to][0]=e[i].w;
                s.push(e[i].to);
            }
    }
}
void swim(int& x,int h)
{
    int i;
    for(i=0;h;i++)
    {
        if(h&1) x=anc[x][i];
        h>>=1;
    }
}
int getlca(int x,int y)
{
    int i,j;
    if(dep[x]<dep[y]) swap(x,y);
    swim(x,dep[x]-dep[y]);
    if(x==y) return x;
    while(true)
    {
        for(i=0;anc[x][i]!=anc[y][i];i++);
        if(!i) return anc[x][0];
        x=anc[x][i-1];y=anc[y][i-1];
    }
}
int query(int x,int y)
{
    int i,ret=9999999,h;
    h=dep[y]-dep[x];
    for(i=depth;i>=0;i--)
        if((1<<i)<=h)
        {
            h-=(1<<i);
            ret=min(ret,g[y][i]);
            y=anc[y][i];
        }
    return ret;
}
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
int main()
{
    int i,j,u,v,w,fx,fy,lca;
    n=read();m=read();
    for(i=1;i<=m;i++)
        line[i].l=read(),line[i].r=read(),line[i].w=read();
    sort(line+1,line+1+m,cmp);
    for(i=1;i<=n;i++) f[i]=i;
    for(i=1;i<=m;i++)
    {
        u=line[i].l;v=line[i].r;w=line[i].w;
        fx=find(u);fy=find(v);
        if(fx!=fy)
        {
            f[fx]=fy;cnt++;
            add(u,v,w);add(v,u,w);
            if(cnt==n-1) break;
        }
    }
    for(i=1;i<=n;i++)
        for(j=0;j<depth;j++)
            g[i][j]=9999999;
    bfs(1);
    q=read();
    for(i=1;i<=q;i++)
    {
        u=read();v=read();
        if(find(u)!=find(v)){puts("-1");continue;}
        lca=getlca(u,v);
        ans=min(query(lca,u),query(lca,v));
        printf("%d\n",ans);
    }
    return 0;
}

【CODEVS 3287】【NOIP2013】火车运输