noip2013 货车运输

传送门:https://www.luogu.org/problem/show?pid=1967

题目描述

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

输入格式

输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道

路。 接下来 m 行每行 3 个整数 x、 y、 z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意: x 不等于 y,两座城市之间可能有多条道路 。

接下来一行有一个整数 q,表示有 q 辆货车需要运货。

接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意: x 不等于 y 。

输出格式

输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货

车不能到达目的地,输出-1。

样例君

输入

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

输出

3

-1

3

说明

对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q< 1,000;

对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q< 1,000;

对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q< 30,000,0 ≤ z ≤ 100,000。

蒟蒻吐槽

  这道题的数据很良心,考试的时候,不会写树上倍增的我,无奈写了个树上增(逃,居然A了,洛谷上也一样,害怕。

  这道题其实就是最大生成树之后,然后求两点间路径上最小的权值,所以跑最大生成树。在询问的时候提前看一下两个点联不联通就可以了。

  我会附上我的两个代码,一个是很迷醉的树上增,一个是蒟蒻学习了树上倍增之后写的树上倍增版本的。关于树上倍增版本的蒟蒻建议可以去百度一下hzwdalao的网站,传送门:http://hzwer.com/1344.html

代码

树上增(手动滑稽)

#include<cstdio>
#include<algorithm>
using namespace std;

const int N=10010;
const int M=50010;
const int inf=2147483647;

struct edge
{
    int to,last,lon;
}a[M],e[M*2];
int fa[N],faa[N],dis[N],dep[N],n,m,fax,fay;
int head[N],cnt;

bool cmp(edge _,edge __)
{
    return _.lon>__.lon;
}

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

inline int find(int _)
{
    if(_==fa[_])return _;
    return fa[_]=find(fa[_]);
}

inline void add(int u,int v,int x)
{
    cnt++;
    e[cnt].to=v;
    e[cnt].lon=x;
    e[cnt].last=head[u];
    head[u]=cnt;
}

void dfs(int u,int dp,int fa1)
{
    faa[u]=fa1;dep[u]=dp;
    for(int i=head[u];i;i=e[i].last)
    {
        int v=e[i].to;        
        if(v!=fa1)
        {
            dfs(v,dp+1,u);
            dis[v]=e[i].lon;
        }
    }
}

int work(int u,int v)
{
    int ans=inf;
    if(dep[u]>dep[v])swap(u,v);
    while(dep[v]>dep[u])
    {
        ans=min(ans,dis[v]);
        v=faa[v];
    }
    while(faa[u]!=faa[v])
    {
        ans=min(ans,min(dis[u],dis[v]));
        u=faa[u];v=faa[v];        
    }
    if(u!=v)ans=min(ans,min(dis[u],dis[v]));
    printf("%d
",ans);
}

int main()
{
    freopen("truck.in","r",stdin);
    freopen("truck.out","w",stdout);
    int x,y,z,ct=0,q;
    n=read();m=read();
    for(int i=1;i<=n;++i)
    fa[i]=i;
    for(int i=1;i<=m;++i)
    {
        x=read();y=read();z=read();
        a[i].last=x;a[i].to=y;a[i].lon=z;
    }
    sort(a+1,a+m+1,cmp);
    for(int i=1;i<=m;++i)
    {
        fax=find(a[i].last);fay=find(a[i].to);
        if(fax!=fay)
        {
            ct++;
            fa[fay]=fax;
            add(a[i].last,a[i].to,a[i].lon);
            add(a[i].to,a[i].last,a[i].lon);
        }
        if(ct==n-1)break;
    }
    for(int i=1;i<=n;++i)
    {
        if(fa[i]==i)dfs(i,0,i);
    }
    q=read();
    while(q--)
    {
        x=read();y=read();
        fax=find(x);fay=find(y);
        if(fax!=fay){printf("-1
");continue;}
        work(x,y);
    }
    return 0;
}

树上倍增

#include<cstdio>
#include<algorithm>
using namespace std;

const int N=10010;
const int M=50010;
const int inf=2147483647;

struct edge
{
    int to,last,lon;
}a[M],e[M*2];
int cnt,head[N],faa[N],n,m;
int fa[N][20],dis[N][20],vis[N],fax,fay,dep[N];

bool cmp(edge _,edge __)
{
    return _.lon>__.lon;
}

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

inline void add(int u,int v,int x)
{
    cnt++;
    e[cnt]=(edge){v,head[u],x};
    head[u]=cnt;
}

inline int find(int _)
{
    if(_==faa[_])return _;
    return faa[_]=find(faa[_]);
}

void kruskal()
{
    int ct=0;
    for(int i=1;i<=n;++i)
    faa[i]=i;
    sort(a+1,a+m+1,cmp);
    for(int i=1;i<=m;++i)
    {
        fax=find(a[i].last);fay=find(a[i].to);
        if(fax==fay)continue;
        faa[fay]=fax;
        ct++;
        add(a[i].last,a[i].to,a[i].lon);
        add(a[i].to,a[i].last,a[i].lon);
        if(ct==n-1)break;
    }
}

void dfs(int u)
{
    vis[u]=1;
    for(int i=1;i<=16;++i)
    {
        if(dep[u]<(1<<i))break;
        fa[u][i]=fa[fa[u][i-1]][i-1];
        dis[u][i]=min(dis[u][i-1],dis[fa[u][i-1]][i-1]);
    }
    for(int i=head[u];i;i=e[i].last)
    {
        int v=e[i].to;
        if(vis[v])continue;
        dep[v]=dep[u]+1;
        fa[v][0]=u;
        dis[v][0]=e[i].lon;
        dfs(v);
    }
    return;
}

int lca(int u,int v)
{
    if(dep[u]>dep[v])swap(u,v);
    int ch=dep[v]-dep[u],ans=inf;
    for(int i=16;i>=0;--i)
        if(ch&(1<<i))
        {            
            ans=min(ans,dis[v][i]);
            v=fa[v][i];
        }
    if(u==v)return ans;
    for(int i=16;i>=0;--i)
        if(fa[u][i]!=fa[v][i])
        {        
            ans=min(ans,min(dis[u][i],dis[v][i]));
            u=fa[u][i];v=fa[v][i];
        }
    if(fa[u][0]==v)return ans;
    return min(ans,min(dis[u][0],dis[v][0]));
}

int main()
{
    int q,x,y;
    n=read();m=read();
    for(int i=1;i<=m;++i)
    {
        a[i].last=read();
        a[i].to=read();
        a[i].lon=read();
    }    
    kruskal();
    for(int i=1;i<=n;++i)
    if(!vis[i])dfs(i);
    q=read();
    while(q--)
    {
        x=read();y=read();
        fax=find(x);fay=find(y);
        if(fax!=fay){printf("-1
");continue;}
        printf("%d
",lca(x,y));
    }
    return 0;
} 
原文地址:https://www.cnblogs.com/mofangk/p/7737903.html