P1967 货车运输(倍增LCA,生成树)
阅读原文时间:2023年07月08日阅读:1

https://www.luogu.org/problemnew/show/P1967

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

输入格式:

第一行有两个用一个空格隔开的整数n,m,表示 AA 国有n 座城市和 m条道路。

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

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

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

输出格式:

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

输入样例#1: 复制

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

输出样例#1: 复制

3
-1
3

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

对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q< 1,0000<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,0000<n<10,000,0<m<50,000,0<q<30,000,0≤z≤100,000。

首先对图建立最大生成树,

倍增LCA维护树上两点之间最小距离。

注意有重边和多个连通分量的情况。

#include
using namespace std;
#define mp make_pair
const int N=10010,M=50010;
struct edge{
int x,y,c;
}ed[M];
bool cmp(edge &a,edge &b){
return a.c>b.c;
}
int f[N];
int findroot(int x){
if(f[x]==x) return x;
return f[x]=findroot(f[x]);
}
void merge(int a,int b){
int f1=findroot(a),f2=findroot(b);
if(f1!=f2){
f[f1]=f2;
}
}
int n,m;
vector> a[N];
map,int > ump;
int d[N],fa[N][31],v[N][31],lg[N];
void dfs(int u,int last){
d[u]=d[last]+1;
v[u][0]=ump[mp(u,last)];
fa[u][0]=last;
for(int i=1;i<=lg[d[u]]-1;i++){
fa[u][i]=fa[fa[u][i-1]][i-1];
v[u][i]=min(v[u][i-1],v[fa[u][i-1]][i-1]);
}

for(auto to:a\[u\]){  
    if(to.first!=last){  
        dfs(to.first,u);  
    }  
}  

}

int lca(int x,int y){
int dis=0x3f3f3f3f;
if(d[x]d[y]){
dis=min(dis,v[x][lg[d[x]-d[y]]-1]);
x=fa[x][lg[d[x]-d[y]]-1];
}
if(x==y) return dis;
for(int i=lg[d[x]]-1;i>=0;i--){
if(fa[x][i]!=fa[y][i]){
dis=min(dis,min(v[x][i],v[y][i]));
x=fa[x][i];
y=fa[y][i];
}
}

return min(dis,min(v\[x\]\[0\],v\[y\]\[0\]));  

}
int main(){
scanf("%d %d",&n,&m);
for(int i=0;i<m;i++){
int x,y,c;
if(x==y) continue;
scanf("%d %d %d",&ed[i].x,&ed[i].y,&ed[i].c);
}
sort(ed,ed+m,cmp);
for(int i=1;i<=n;i++){
f[i]=i;
lg[i]=lg[i-1]+(1<<lg[i-1]==i);//log2(i)+1;
}

int cnt=0;  
for(int i=0;i<m;i++){  
    int x=ed\[i\].x,y=ed\[i\].y;  
    int f1=findroot(x),f2=findroot(y);  
    if(f1!=f2){  
        f\[f1\]=f2;  
        a\[x\].push\_back(mp(y,ed\[i\].c));  
        a\[y\].push\_back(mp(x,ed\[i\].c));  
        ump\[mp(x,y)\]=ump\[mp(y,x)\]=ed\[i\].c;  
        cnt++;  
        if(cnt==n-1) break;  
    }  
}

//多个连通分量  
for(int i=1;i<=n;i++){  
    if(f\[i\]==i){  
        ump\[mp(i,0)\]=0;  
        dfs(i,0);  
    }  
} 

int Q;  
scanf("%d",&Q);  
for(int i=1;i<=Q;i++){  
    int x,y;  
    scanf("%d %d",&x,&y);  
    if(findroot(x)!=findroot(y)) printf("-1\\n");  
    else printf("%d\\n",lca(x,y));  
} 

return 0;  

}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章