传送门:https://www.smartoj.com/p/2511
题目Problem
[NOIP2013T3]货车运输
Time Limit: 1000ms Memory Limit: 131072KB
描述Descript.
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入Input
第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。
接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。
接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。
输出Output
输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。
样例Sample
输入数据
4 3 1 2 4 2 3 3 3 1 1 3 1 3 1 4 1 3
输出数据
3 -1 3
备注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。
做法:不难发现这题满足贪心性质:最大生成树,有了这个性质,我们就有60分了。。对于询问,如果你的并查集是启发式合并的,你就AC了。。启发式合并明天在写,今天写的是树上路径倍增LCA。
#include<set> #include<queue> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N = 50010*2; const int M = 50010; #define logn 16 #define pauses printf("tests\n!!!"); #define For(i,n) for(int i=1;i<=n;i++) #define Rep(i,l,r) for(int i=l;i<=r;i++) #define Down(i,r,l) for(int i=r;i>=l;i--) struct edge{ int s,t,next,w; int old; }E[M*2],TE[M]; int q,n,m,Es,s,t,w; int f[N],fa[N][logn+20],deep[N],Min[N][logn+20]; int head[N]; bool vis[N]; void makelist(int s,int t,int w){ E[Es].s = s;E[Es].t = t; E[Es].w = w; E[Es].next = head[s];E[Es].old = Es; head[s] = Es++; } bool cmp(edge A,edge B){ return A.w > B.w; } int find(int i){ return (f[i]==i)?(i):(find(f[i])); } void init(){ freopen("truck.in","r",stdin); freopen("truck.out","w",stdout); memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); For(i,n) f[i] = i; For(i,m){ scanf("%d%d%d",&s,&t,&w); TE[i].s = s;TE[i].t = t;TE[i].w = w; } sort(TE+1,TE+m+1,cmp); For(i,m){ int fx = find(TE[i].s) , fy = find(TE[i].t); if(fx!=fy) { f[fx] = fy; makelist(TE[i].s,TE[i].t,TE[i].w); makelist(TE[i].t,TE[i].s,TE[i].w); } } } void DFS(int i){ vis[i] = true; for(int p=head[i];p!=-1;p=E[p].next) if(!vis[E[p].t]){ int v = E[p].t;fa[v][0] = i; deep[v] = deep[i] + 1; Min[v][0] = E[p].w; For(j,logn){ fa[v][j] = fa[fa[v][j-1]][j-1]; Min[v][j] = min(Min[v][j-1],Min[fa[v][j-1]][j-1]); } DFS(v); } } int LCA(int u,int v){ int ans = 2147483647;if(deep[u] < deep[v]) swap(u,v); int d = deep[u] - deep[v]; Rep(i,0,logn) if((1<<i)&d) {ans = min(ans,Min[u][i]);u = fa[u][i];} if(u==v) return ans; Down(i,logn,0) if(fa[u][i]!=fa[v][i]){ ans = min(min(Min[u][i],Min[v][i]),ans); u = fa[u][i];v = fa[v][i]; } if(u!=v){ ans = min(ans,min(Min[u][0],Min[v][0])); u = fa[u][0]; } return ans; } int main(){ init(); For(i,n) if(!deep[i]){deep[i] = 1;DFS(i);} scanf("%d",&q); For(i,q){ scanf("%d%d",&s,&t); if(find(s)!=find(t)) printf("%d\n",-1); else printf("%d\n",LCA(s,t)); } return 0; }