NOIP2013货车运输

NOIP2013货车运输


题目描述

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。
数据范围:n最大10000,m最大50000,q为30000,z为100000.

输出

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

样例输入

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

样例输出

3
-1
3

做法

两点之间尽可能大的最小承重路径一定在最大生成树上,于是问题转化为查询最大生成树上,两点之间的最小边的查询,可以倍增,也可以树剖。注意还有可能不能互相到达。

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;
const int N = 10010;
const int M = 50100;
const int inf = 0x3f3f3f3f;
inline int read() {
    char c=getchar(); int x=0,f=1;
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}
using namespace std;
struct edge{int u,v,nxt,w;}E[M<<1],E0[M<<1];
int h[N],cc;
void add(int u,int v,int z) {
    E[cc].v=v;E[cc].w=z;E[cc].nxt=h[u];h[u]=cc;++cc;
}
bool cmp(edge a,edge b) {return a.w > b.w;}
int n,m;
int f[N][22],mn[N][22],fa[N];
int find(int x) {
    if(x==fa[x])return x;
    return fa[x]=find(fa[x]);
}
void merge(int x,int y) {
    x=find(x), y =find(y);
    if(x!=y) fa[x]=y;
}
void krus() {
    sort(E0+1,E0+1+m,cmp);
    rep(i,1,m) {
        int tx = find(E0[i].u), ty = find(E0[i].v);
        if(tx!=ty) {
            merge(tx,ty);
            add(E0[i].u,E0[i].v,E0[i].w);
            add(E0[i].v,E0[i].u,E0[i].w);
        }
    }
}
bool vis[N];
int dep[N];
void dfs(int u,int pre) {
    vis[u] = 1;
    f[u][0] = pre;
    for(int i=h[u];~i;i=E[i].nxt) {
        int v = E[i].v;
        if(!vis[v]&&v!=pre) {
            dep[v]=dep[u]+1;
            mn[v][0] = E[i].w;
            dfs(v,u);
            for(int j=1;j<=20;++j) f[v][j] = f[f[v][j-1]][j-1];
            for(int j=1;j<=20;++j) mn[v][j] = min(mn[v][j-1],mn[f[v][j-1]][j-1]);
        }
    }
}
void init() {
    memset(mn,inf,sizeof(mn));
    krus();
    rep(i,1,n)if(!vis[i])dfs(i,0);
//    rep(i,1,n) {
//        printf("%d :\n",i);
//        printf("dep[%d] = %d\n",i,dep[i]);
//        rep(j,0,3) printf("fa[%d][%d] = %d\n",i,j,f[i][j]);
//        rep(j,0,3) printf("mn[%d][%d] = %d\n",i,j,mn[i][j]);
//    }
}
int lca(int x,int y) {
    if(dep[x] > dep[y]) swap(x,y);
    int tx=x,ty=y;
    for(int d=dep[y]-dep[x],i=0;d;d>>=1,++i) if(d&1) ty = f[ty][i];
    if(tx == ty) return tx;
    for(int i=20;i>=0;--i) {
        if(f[tx][i]==f[ty][i]) continue;
        tx = f[tx][i], ty = f[ty][i];
    }
    return f[tx][0];
}
int ask_mn(int x,int p) {
    int ans = inf, tx=x;
    for(int d=dep[x]-dep[p],i=0;d;d>>=1,++i) if(d&1) {
        ans = min(ans,mn[tx][i]);
        tx = f[tx][i];
    }
    return ans;
}
int ask(int x,int y) {
    if(find(x)!=find(y)) return -1;
    int LCA = lca(x,y);
    return min(ask_mn(x,LCA),ask_mn(y,LCA));
}
int main() {
    n = read(), m =read();
    rep(i,1,n) h[i]=-1,fa[i]=i;
    rep(i,1,m) E0[i].u=read(),E0[i].v=read(),E0[i].w=read();
    init();

    int q = read();
    while(q--) {
        int x=read(), y =read();
        printf("%d\n",ask(x,y));
    }
    return 0;
}
//9 8
//1 2 4
//1 5 3
//2 3 3
//2 4 2
//3 9 2
//3 8 7
//5 7 6
//5 6 7

猜你喜欢

转载自www.cnblogs.com/RRRR-wys/p/9384040.html