NOIP2013货车运输
题目描述 Description
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入描述 Input Description
第一行有两个用一个空格隔开的整数 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 Description
输出共有 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
数据范围及提示 Data Size & 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。
题解
其实本题是模板题,询问森林中两个点的路径上的最小边权,连通性用并查集判一下
可以用树上倍增在logn的复杂度解决一棵树内的一次询问
预处理F(i,j)表示第i个点距离为2^j的祖先,这个可以深搜整棵树再递推一下,复杂度nlogn
G(i,j)表示第i个点到其距离为2^j的祖先上的最小权值,然后用倍增的思想俩个点往上跳一跳更新答案就行
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=201000;
const int inf=0x3f3f3f3f;
struct edge
{
int v,nxt,w;
}edge[maxn*3+100];
int head[maxn],cnt=0;
void add_edge(int u,int v,int w)
{
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].nxt=head[u];
head[u]=cnt++;
}
struct node
{
int x,y,z;
}a[maxn*3+100];
int deg[maxn],fa[maxn][20],dis[maxn][20],vis[maxn];
void bfs(int u)
{
queue<int>q;
q.push(u);
vis[u]=1;
fa[u][0]=u;
deg[u]=0;
while(!q.empty())
{
int now=q.front();
vis[now]=1;
q.pop();
for(int i=1;i<20;i++)
{
fa[now][i]=fa[fa[now][i-1]][i-1];
dis[now][i]=min(dis[now][i-1],dis[fa[now][i-1]][i-1]);
}
for(int i=head[now];i!=-1;i=edge[i].nxt)
{
int to=edge[i].v;
if(to==fa[now][0])
{
continue;
}
deg[to]=deg[now]+1;
dis[to][0]=edge[i].w;
fa[to][0]=now;
q.push(to);
}
}
}
int lca(int u,int v)
{
if(deg[u]>deg[v])
{
swap(u,v);
}
int hu=deg[u],hv=deg[v];
int tu=u,tv=v;
for(int det=hv-hu,i=0;det;det>>=1,i++)
{
if(det&1)
{
tv=fa[tv][i];
}
}
if(tu==tv)
return tu;
for(int i=19;i>=0;i--)
{
if(fa[tu][i]==fa[tv][i])
continue;
tu=fa[tu][i];
tv=fa[tv][i];
}
return fa[tu][0];
}
int cmp(node aa,node bb)
{
return aa.z>bb.z;
}
int pre[maxn];
int findd(int x)
{
int r=x;
while(r!=pre[r])
r=pre[r];
int i=x,j;
while(i!=r)
{
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
int solve(int u,int v)
{
int minn=inf;
int hu=deg[u],hv=deg[v];
int tu=u,tv=v;
for(int det=hu-hv,i=0;det;det>>=1,i++)
{
if(det&1)
{
minn=min(minn,dis[tu][i]);
tu=fa[tu][i];
}
}
return minn;
}
int main ()
{
memset(head,-1,sizeof(head));
cnt=0;
memset(deg,0,sizeof(deg));
memset(fa,0,sizeof(fa));
int m,n;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
}
for(int i=1;i<=n;i++)
{
pre[i]=i;
}
sort(a+1,a+1+m,cmp);
int nn=0;
for(int i=1;i<=m;i++)
{
int tx,ty;
tx=findd(a[i].x);
ty=findd(a[i].y);
if(tx!=ty)
{
pre[ty]=tx;
add_edge(a[i].x,a[i].y,a[i].z);
add_edge(a[i].y,a[i].x,a[i].z);
nn++;
if(nn==n-1)
{
break;
}
}
}
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
bfs(i);
}
}
int p;
scanf("%d",&p);
while(p--)
{
int xx,yy;
scanf("%d%d",&xx,&yy);
if(findd(xx)!=findd(yy))
{
printf("-1\n");
}
else
{
int aa=lca(xx,yy);
printf("%d\n",min(solve(xx,aa),solve(yy,aa)));
}
}
}