洛谷P1967 货车运输
题目描述
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入输出格式
输入格式:
输入文件名为 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 。
输出格式:
输出文件名为 truck.out。
输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货
车不能到达目的地,输出-1。
输入输出样例
说明
对于 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。
解析:第一次打这种利用树上倍增求其他变量的题目,感到了顺序的可怕。。。一直是10分,发现只要交换相邻两行的位置,便100了。。。
为防考试时出错,特此一记。
这道题目很裸的生成树+倍增,很适合当模板打。
但注意: 1.这题和线段树也一样坑。。。得明确更新的顺序:先更新最小值,在更新节点。
2.记得对每棵树进行dfs/bfs。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rint register int
template<class T>
inline void rd( T &x){
x=0;bool f=0;char ch=getchar();
while(!isdigit(ch)) { f=(ch==45);ch=getchar();}
while( isdigit(ch)) { x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?(~x+1):x;}
inline int read(){
int x=0;bool f=0;char ch=getchar();
while(!isdigit(ch)){ f=(ch==45);ch=getchar();}
while( isdigit(ch)){ x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x=f?(~x+1):x;
}
#define man 100010
int m,n,q;
struct link{
int x,y,z;
link(){
z=0;
}
}a[man<<1];
int cmp(link x,link y){
return x.z>y.z;
}
int fa[man];
inline int find(int x){
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
struct edge{
int next,to,dis;
}e[man<<1];
int head[man<<1],num=0;
inline void add(int from,int to,int dis){
e[++num].next=head[from];
e[num].to=to;
e[num].dis=dis;
head[from]=num;
}
int logn,dep[man];
int minn_dis[man][30],f[man][30];
bool vis[man];
void dfs(int s,int father,int depth,int dis){
vis[s]=1;
f[s][0]=father;minn_dis[s][0]=dis;dep[s]=depth;
for(rint i=head[s];i;i=e[i].next){
int to=e[i].to;
if(to==father) continue;
dfs(to,s,depth+1,e[i].dis);
}
return ;
}
/*上述的dfs也可用以下的bfs运行*/
inline void bfs(int s)
{ f[s][0]=-1;dep[s]=0;vis[s]=1;
queue<int>q;q.push(s);
do
{ int u=q.front();q.pop();
for(int i=head[u];i;i=e[i].next)
{ int to=e[i].to;
if(!vis[to])
{ minn_dis[to][0]=e[i].dis;
f[to][0]=u;
dep[to]=dep[u]+1;
q.push(to);
vis[to]=1;
}
}
}while(q.size());
}
inline int LCA(int x,int y)
{ int ans=0x7fffffff;
if(dep[x]>dep[y]) swap(x,y);
for(int i=0;i<logn;i++)
if(((dep[y]-dep[x])>>i)&1) ans=min(ans,minn_dis[y][i]),y=f[y][i];
if(x==y) return ans;
for(int i=logn;i>=0;i--)
if(f[x][i]!=f[y][i])
{ ans=min(ans,min(minn_dis[x][i],minn_dis[y][i]));
x=f[x][i];y=f[y][i];
}
ans=min(ans,min(minn_dis[x][0],minn_dis[y][0]));
return ans;
}
int main(){
memset(minn_dis,0x7f,sizeof(minn_dis));
n=read();m=read();
for(rint i=1;i<=m;i++){
a[i].x=read();a[i].y=read();a[i].z=max(a[i].z,read());
}
for(rint i=1;i<=n;i++) fa[i]=i;
sort(a+1,a+1+m,cmp);
int temp=0;
for(rint i=1;i<=m;i++){
int xx=find(a[i].x),yy=find(a[i].y);
if(xx==yy) continue;
fa[xx]=yy;
add(a[i].x,a[i].y,a[i].z);
add(a[i].y,a[i].x,a[i].z);
temp++;
if(temp==n-1) break;
}
memset(vis,0,sizeof(vis));
for(rint i=1;i<=n;i++)
if(!vis[i]) dfs(i,-1,0,0);
logn=(int)(log(n)/log(2.0))+1;
for(rint j=0;j<=logn;j++)
for(rint i=1;i<=n;i++)
if(f[i][j]<0) f[i][j+1]=-1;
else {
f[i][j+1]=f[f[i][j]][j];
minn_dis[i][j+1]=min(minn_dis[i][j],minn_dis[f[i][j]][j]);
}
q=read();
for(rint i=1;i<=q;i++){
int x=read(),y=read();
if(find(x)!=find(y)) printf("-1
");
else printf("%d
",LCA(x,y));
}
return 0;
}