[NOIP2013 提高组] 货车运输
题目背景
NOIP2013 提高组 D1T3
题目描述
A 国有 n n n 座城市,编号从 1 1 1 到 n n n,城市之间有 m m m 条双向道路。每一条道路对车辆都有重量限制,简称限重。
现在有 q q q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入格式
第一行有两个用一个空格隔开的整数 $ n,m$,表示 A 国有 $ n$ 座城市和 m m m 条道路。
接下来 m m m 行每行三个整数 x , y , z x, y, z x,y,z,每两个整数之间用一个空格隔开,表示从 $x $ 号城市到 $ y $ 号城市有一条限重为 z z z 的道路。
注意: x ≠ y x \neq y x=y,两座城市之间可能有多条道路 。
接下来一行有一个整数 q q q,表示有 q q q 辆货车需要运货。
接下来 q q q 行,每行两个整数 x , y x,y x,y,之间用一个空格隔开,表示一辆货车需要从 x x x 城市运输货物到 y y y 城市,保证 x ≠ y x \neq y x=y
输出格式
共有 q q q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。
如果货车不能到达目的地,输出 − 1 -1 −1。
样例 #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 % 30\% 30% 的数据, 1 ≤ n < 1000 1 \le n < 1000 1≤n<1000, 1 ≤ m < 10 , 000 1 \le m < 10,000 1≤m<10,000, 1 ≤ q < 1000 1\le q< 1000 1≤q<1000;
对于 60 % 60\% 60% 的数据, 1 ≤ n < 1000 1 \le n < 1000 1≤n<1000, 1 ≤ m < 5 × 1 0 4 1 \le m < 5\times 10^4 1≤m<5×104, 1 ≤ q < 1000 1 \le q< 1000 1≤q<1000;
对于 100 % 100\% 100% 的数据, 1 ≤ n < 1 0 4 1 \le n < 10^4 1≤n<104, 1 ≤ m < 5 × 1 0 4 1 \le m < 5\times 10^4 1≤m<5×104,$1 \le q< 3\times 10^4 $, 0 ≤ z ≤ 1 0 5 0 \le z \le 10^5 0≤z≤105。
详解
启发式合并+并查集:
先存边,按边长排序(贪)
然后保存每次询问(离线)
从小范围开始解决
并查集取消按秩合并与路径压缩合并
然后让小问题作为大问题的优先问题
合并时让大问题回归小问题,保存答案
代码实现!
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
#define int long long
int pre[MAXN],q,n,m,ans[MAXN];
struct node{int st,ed,v;
}Edge[MAXN];
struct Query{int ed,id;
};
vector<Query> Q[MAXN];
bool cmpEdge(node A,node B){return A.v>B.v;
}
int Find(int x){while(1){if(pre[x]==x) return x;x=pre[x];}
}
void merge(int x,int y,int val){int fx=Find(x),fy=Find(y);if(fx==fy) return;if(Q[fx].size()>Q[fy].size()) swap(fx,fy);pre[fx]=fy;for(int i=0;i<Q[fx].size();i++){int t=Q[fx][i].ed,id=Q[fx][i].id;if(ans[id]!=-1) continue;int ft=Find(t);if(ft==fy) ans[id]=val;}for(int i=0;i<Q[fx].size();i++) Q[fy].push_back(Q[fx][i]);
}
signed main()
{memset(ans,-1,sizeof(ans));scanf("%d %d",&n,&m);for(int i=1;i<=m;i++){int st,ed,v;scanf("%d %d %d",&st,&ed,&v);Edge[i].st=st,Edge[i].ed=ed,Edge[i].v=v;}sort(Edge+1,Edge+1+m,cmpEdge);scanf("%d",&q);for(int i=1;i<=q;i++){int x,y;scanf("%d %d",&x,&y);Q[x].push_back((Query){y,i});Q[y].push_back((Query){x,i});}for(int i=1;i<=n;i++) pre[i]=i;for(int i=1;i<=m;i++) merge(Edge[i].st,Edge[i].ed,Edge[i].v);for(int i=1;i<=q;i++) printf("%d\n",ans[i]);return 0;
}