洛谷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; }