货车运输
Description
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
Input
输入文件名为 truck.in。
输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道
路。 接下来 m 行每行 3 个整数 x、 y、 z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意: x 不等于 y,两座城市之间可能有多条道路 。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意: x 不等于 y 。
Output
-输出文件名为 truck.out。
输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货
车不能到达目的地,输出-1。
Sample Input
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
Sample Output
3
-1
3
Hint
对于 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。
题解
在最大生成树上树链剖分,用并查集判断是否可达
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int infty=1<<29;
int N,M,Q;
struct edge
{
int to,nxt,cost;
}g[200050];
struct data
{
int u,v,w;
}e[500050];
struct segmentnode
{
int mn;
}seg[400050];
int ecnt,head[100050];
int bel[100050];
int vis[100050],val[100050];
int place;
int parent[100050],deep[100050],sz[100050],tid[100050],top[100050],rnk[100050];
inline void addedge(int u,int v,int w)
{
g[ecnt]=(edge){v,head[u],w},head[u]=ecnt++;
g[ecnt]=(edge){u,head[v],w},head[v]=ecnt++;
}
int comp(const data & a, const data & b){return a.w>b.w;}
int findset(int a){return a==bel[a]?a:bel[a]=findset(bel[a]);}
void kruskal()
{
sort(e+1,e+M+1,comp);
for(int i=1;i<=M;i++)bel[i]=i;
for(int i=1;i<=M;i++)
{
int u=e[i].u,v=e[i].v,w=e[i].w;
if(findset(u)==findset(v))continue;
bel[findset(u)]=findset(v);
addedge(u,v,w);
}
}
void dfs(int root)
{
vis[root] = 1;
for(int i=head[root];~i;i=g[i].nxt)
{
int v=g[i].to;if(vis[v])continue;
dfs(v);
}
}
void getdeep(int root,int step,int fa)
{
parent[root]=fa,deep[root]=step,sz[root]=1;
for(int i=head[root];~i;i=g[i].nxt)
{
int v=g[i].to,w=g[i].cost;
if(v == fa)continue;
getdeep(v,step+1,root);
sz[root]+=sz[v],val[v]=w;
}
}
void devide(int root,int chain,int fa)
{
top[root]=chain,tid[root]=++place,rnk[place]=root;
int k=0;
for(int i=head[root];~i;i=g[i].nxt)
{
int v=g[i].to;if(v==fa)continue;
if(sz[v]>sz[k])k=v;
}if(k==0)return;devide(k,chain,root);
for(int i=head[root];~i;i=g[i].nxt)
{
int v=g[i].to;if(v==fa||v==k)continue;
devide(v,v,root);
}
}
inline void pushup(int root)
{
seg[root].mn=min(seg[root<<1].mn,seg[root<<1|1].mn);
}
void build(int root,int l,int r)
{
if(l==r){seg[root].mn=val[rnk[l]];return;}
int mid=(l+r)>>1;
build(root<<1,l,mid),build(root<<1|1,mid+1,r);
pushup(root);
}
int getmin(int root,int l,int r,int a,int b)
{
if(l==a&&r==b)return seg[root].mn;
int mid=(l+r)>>1;
if(b<=mid)return getmin(root<<1,l,mid,a,b);
else if(a>mid)return getmin(root<<1|1,mid+1,r,a,b);
else return min(getmin(root<<1,l,mid,a,mid),getmin(root<<1|1,mid+1,r,mid+1,b));
}
int getmin(int a,int b)
{
int res=infty;
while(top[a]!=top[b])
{
if(deep[top[a]]>deep[top[b]])swap(a,b);
res=min(res,getmin(1,1,N+1,tid[top[b]],tid[b]));
b=parent[top[b]];
}if(deep[a]>deep[b])swap(a,b);
if(a!=b)res=min(res,getmin(1,1,N+1,tid[a]+1,tid[b]));
return res;
}
int main()
{
while(scanf("%d%d",&N,&M)!=EOF)
{
memset(head,-1,sizeof(head));
ecnt=place=0;
for(int i=1;i<=M;i++)
{
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}
kruskal();
memset(vis,0,sizeof(vis));
deep[N+1]=1;
for(int i=1;i<=N;i++)
{
if(!vis[i])
{
addedge(N+1,i,infty);
dfs(N+1);
}
}
getdeep(N+1,1,0);
devide(N+1,N+1,0);
build(1,1,N+1);
scanf("%d",&Q);
for(int i=1,u,v;i<=Q;i++)
{
scanf("%d%d",&u,&v);
if(findset(u)!=findset(v))
{
printf("-1\n");
continue;
}
printf("%d\n",getmin(u,v));
}
}
return 0;
}