题目描述
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。
输入输出样例
输入样例#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,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。
题解:
最大生出树+树链剖分
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<cmath> 6 #include<algorithm> 7 #include<vector> 8 #include<stack> 9 #include<queue> 10 #include<map> 11 #define RG register 12 #define IL inline 13 #define pi acos(-1.0) 14 #define ll long long 15 #define ls x<<1 16 #define rs x<<1|1 17 #define MID int mid=(l+r)>>1; 18 #define inf 1<<30 19 using namespace std; 20 21 const int maxn = 10010; 22 const int maxm = 50010; 23 24 int gi() { 25 char ch=getchar(); int x=0; 26 while(ch<'0' || ch>'9') ch=getchar(); 27 while(ch>='0' && ch<='9') {x=10*x+ch-'0';ch=getchar();} 28 return x; 29 } 30 31 int n,m,k,z,q,fa[maxm]; 32 int nxt[maxm*2],to[maxm*2],dis[maxm*2],h[maxn],e_num; 33 int siz[maxn],son[maxn],top[maxn],dep[maxn],fat[maxn],w[maxn],dfn[maxn],rev[maxn]; 34 int tr[maxn*4]; 35 bool bj[maxn]; 36 struct EDGE { 37 int x,y,v; 38 }e[maxm],E[maxm]; 39 40 bool cmp(EDGE a, EDGE b) { 41 return a.v>b.v; 42 } 43 44 int find(int x) { 45 if(fa[x]!=x) fa[x]=find(fa[x]); 46 return fa[x]; 47 } 48 49 void add(int x, int y, int v) { 50 nxt[++e_num]=h[x]; 51 to[e_num]=y; 52 dis[e_num]=v; 53 h[x]=e_num; 54 } 55 56 void dfs1(int u) { 57 siz[u]=1; 58 for(int i=h[u]; i; i=nxt[i]) { 59 int v=to[i]; 60 if(v==fat[u]) continue; 61 fat[v]=u; 62 dep[v]=dep[u]+1; 63 w[v]=dis[i]; 64 dfs1(v); 65 if(siz[v]>siz[son[u]]) son[u]=v; 66 siz[u]+=siz[v]; 67 } 68 } 69 70 void dfs2(int u) { 71 dfn[u]=++z;rev[z]=u; 72 if(son[u]) top[son[u]]=top[u],dfs2(son[u]); 73 for(int i=h[u]; i; i=nxt[i]) { 74 int v=to[i]; 75 if(v==fat[u] || v==son[u]) continue; 76 top[v]=v,dfs2(v); 77 } 78 } 79 80 void build(int x, int l, int r) { 81 if(l==r) {tr[x]=w[rev[l]];return;} 82 MID; 83 build(ls,l,mid),build(rs,mid+1,r); 84 tr[x]=min(tr[ls],tr[rs]); 85 } 86 87 int query(int x, int l, int r, int ql, int qr) { 88 if(l>=ql && r<=qr) return tr[x]; 89 MID; 90 if(qr<=mid) return query(ls,l,mid,ql,qr); 91 else if(ql>mid) return query(rs,mid+1,r,ql,qr); 92 return min(query(ls,l,mid,ql,mid),query(rs,mid+1,r,mid+1,qr)); 93 } 94 95 int lca(int x, int y) { 96 int tmp=inf; 97 while(top[x]!=top[y]) { 98 if(dep[top[x]]>dep[top[y]]) tmp=min(tmp,query(1,1,z,dfn[top[x]],dfn[x])),x=fat[top[x]]; 99 else tmp=min(tmp,query(1,1,z,dfn[top[y]],dfn[y])),y=fat[top[y]]; 100 } 101 if(x==y) return tmp; 102 else { 103 if(dep[x]>dep[y]) swap(x,y); 104 tmp=min(tmp,query(1,1,z,dfn[x]+1,dfn[y])); 105 } 106 return tmp; 107 } 108 109 int main() { 110 n=gi(),m=gi(); 111 for(int i=1; i<=m; i++) { 112 E[i].x=gi(),E[i].y=gi(),E[i].v=gi(); 113 fa[i]=i; 114 } 115 sort(E+1,E+m+1,cmp); 116 for(int i=1; i<=m; i++) { 117 int x=find(E[i].x),y=find(E[i].y); 118 if(x==y) continue; 119 e[++k].x=E[i].x,e[k].y=E[i].y,e[k].v=E[i].v; 120 fa[y]=x; 121 if(k==n-1) break; 122 } 123 for(int i=1; i<=k; i++) { 124 bj[e[i].x]=1,bj[e[i].y]=1; 125 add(e[i].x,e[i].y,e[i].v); 126 add(e[i].y,e[i].x,e[i].v); 127 } 128 dep[1]=1,fat[1]=1,top[1]=1,w[1]=inf; 129 dfs1(1),dfs2(1),build(1,1,z); 130 q=gi(); 131 for(int i=1; i<=q; i++) { 132 int x=gi(),y=gi(); 133 if(!bj[x] || !bj[y]) printf("-1 "); 134 else printf("%d ", lca(x,y)); 135 } 136 }
总结——图上最小(大)边的最大(小)化问题
1、路径上最小边的最大值:最大生成树+树链最小值
2、路径上最大边的最小值:最小生成树+树链最大值