洛谷 P1967 货车运输 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。

题目链接:https://www.luogu.org/problem/show?pid=1967

题目描述

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。

分析:

(读题10min,写题15min,Debug两小时系列)

要令货车载重最大,需要求最大生成树,货车的路径一定在最大生成树上。

然后在最大生成树上求出货车路径上的最小载重量,即为答案。

求出最大生成树之后暴力求最小载重量应该能拿到60分,具体我并不清楚,一直在试图写正解qwq

(考场上如果遇到了,时间不足1h的话就优先60分吧,我做这道题的时间几乎就一场NOIP了...)

满分做法:最近公共祖先求出从x到y路径上的最小权值。F[i][j]表示从i向上走2^j步到达的节点,

G[i][j]表示从i向上走2^j步过程中的最小权值。整个过程就是多维护了一个G数组,以及lca函数中

返回的答案是ans,其他与最近公共祖先无异。

AC代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cmath>
  4 #include<cstring>
  5
  6 const int MAXN = 10002;
  7 const int MAXM = 50002;
  8 inline void Read(int &x)
  9 {
 10     char ch = getchar(),c = ch;x = 0;
 11     while(ch < ‘0‘ || ch > ‘9‘) c = ch,ch = getchar();
 12     while(ch >= ‘0‘ && ch <= ‘9‘) x = (x<<1)+(x<<3)+ch-‘0‘,ch = getchar();
 13     if(c == ‘-‘) x = -x;
 14 }
 15
 16 inline int Min(int a,int b)
 17 {return a<b?a:b;}
 18
 19 inline int Max(int a,int b)
 20 {return a>b?a:b;}
 21
 22 inline int Abs(int a)
 23 {return a>=0?a:-a;}
 24
 25 inline void Swap(int &a,int &b)
 26 {int t = a;a = b,b = t;}
 27
 28 int n,m,f,t,v,x,y,q,tot;
 29 int Head[MAXM<<1],Fa[MAXN],Fun[MAXN][16],G[100002][16],Deep[MAXN];
 30
 31 struct Edge
 32 {
 33     int f,t,v,nxt;
 34 }e[MAXM<<1],New[MAXN<<1];
 35
 36 int cmp(Edge a,Edge b)
 37 {return a.v > b.v;}
 38
 39 void Newbuild_gw(int f,int t,int v)
 40 {
 41     New[++tot].f = f,New[tot].t = t;
 42     New[tot].v = v,New[tot].nxt = Head[f];
 43     Head[f] = tot;
 44 }
 45
 46 int find_gw(int x)
 47 {return Fa[x]==x?x:Fa[x]=find_gw(Fa[x]);}
 48
 49 bool merge_gw(int a,int b)
 50 {
 51     a = find_gw(a),b = find_gw(b);
 52     if(a != b){
 53         Fa[a] = b;
 54         return true;
 55     }
 56     return false;
 57 }
 58
 59 void dfs_gw(int now)
 60 {
 61     for(int i = Head[now];i;i = New[i].nxt)
 62     {
 63         int tto = New[i].t;
 64         if(Deep[tto]) continue;
 65         Deep[tto] = Deep[now]+1;
 66         Fun[tto][0] = now;
 67         G[tto][0] = New[i].v;
 68         dfs_gw(tto);
 69     }
 70 }
 71
 72 void Init_gw()
 73 {
 74     Deep[1] = 0;
 75     dfs_gw(1);
 76     for(int j = 1;j <= 15;++ j)
 77         for(int i = 1;i <= n;++ i)
 78         {
 79             Fun[i][j] = Fun[Fun[i][j-1]][j-1];
 80             G[i][j] = Min(G[i][j-1],G[Fun[i][j-1]][j-1]);
 81         }
 82 }
 83
 84 int Ask_gw(int x,int y)
 85 {
 86     int Ans = 214748364;
 87     if(Deep[x] > Deep[y]) Swap(x,y);
 88     for(int j = 15;j >= 0;-- j)
 89         if(Deep[y] >= Deep[x]+(1<<j))
 90             Ans = Min(Ans,G[y][j]),y = Fun[y][j];
 91     if(x == y) return Ans;
 92     for(int j = 15;j >= 0;-- j)
 93         if(Fun[x][j] != Fun[y][j])
 94         {
 95             Ans = Min(Ans,Min(G[x][j],G[y][j]));
 96             x = Fun[x][j];
 97             y = Fun[y][j];
 98         }
 99     if(!Fun[x][0]) return -1;
100     Ans = Min(Ans,Min(G[y][0],G[x][0]));
101     return Ans;
102 }
103
104 int main()
105 {
106 //    freopen("1.txt","r",stdin);
107     Read(n),Read(m);;
108     for(int i = 1;i <= m;++ i)
109         Read(e[i].f),Read(e[i].t),Read(e[i].v);
110     std::sort(e+1,e+1+m,cmp);
111     for(int i=1;i<=n;++i) Fa[i]=i;
112     for(int i = 1;i <= m;++ i)
113         if(merge_gw(e[i].f,e[i].t))
114         {
115             Newbuild_gw(e[i].f,e[i].t,e[i].v);
116             Newbuild_gw(e[i].t,e[i].f,e[i].v);
117         }
118     Init_gw();
119     Read(q);
120     for(int i = 1;i <= q;++ i)
121     {
122         Read(x),Read(y);
123         printf("%d\n",Ask_gw(x,y));
124     }
125     return 0;
126 }
时间: 2024-11-08 18:18:12

洛谷 P1967 货车运输 题解的相关文章

洛谷 P1967 货车运输 Label: 倍增LCA &amp;&amp; 最小瓶颈路

题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z

洛谷P1967 货车运输

题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z

洛谷P1967货车运输

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define N 100010#define INF 0xfffffusing namespace std;int n, m, q, x, y, cnt;int head[N], nxt[N*2], to[N*2], w[N*2], p[N*5], f[N][20], minv[N][20], dep[N];s

洛谷T1967 货车运输 Kruskal最大生成树&amp;&amp;倍增LCA

这题的题意是:对于每组x.y,求x到y路径上最小边权的最大值.于是可以使用最大生成树,因为最大生成树满足性质:生成树中最小边权最大,且任意两点间路径上最小边权最大.有了树之后,要求路径,那就要考虑LCA.首先,这题可以树剖,但是我太懒了,于是写了倍增233具体搞法:Kruskal跑出最大生成树,然后在树上倍增LCA,处理出2个数组:fa[][]和minv[][]:fa[][]表示第2^k个父亲是谁,minv[][]表示当前节点到其第2^k个父亲的路径上的最小边权.对于每次查询,在求LCA的同时,

洛谷P1967 [NOIP2013提高组Day1T2]货车运输

P1967 货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y

洛谷P2832 行路难 分析+题解代码【玄学最短路】

洛谷P2832 行路难 分析+题解代码[玄学最短路] 题目背景: 小X来到了山区,领略山林之乐.在他乐以忘忧之时,他突然发现,开学迫在眉睫 题目描述: 山区有n座山.山之间有m条羊肠小道,每条连接两座山,只能单向通过,并会耗费小X一定时间. 小X现在在1号山,他的目的是n号山,因为那里有火车站. 然而小X的体力是有限的.他每通过一条羊肠小道,就会变得更疲劳,导致他通过任意一条羊肠小道的时间都增加1. 输入格式: 第一行两个数,n,m 第2行到第m+1行,每行3个数A,B,C,表示A.B之间有一条

洛谷 P1219 八皇后 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1219 题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序列2 4 6 1 3 5来描述,第i个数字表示在第i行的相应位置有一个棋子,如下: 行号 1 2 3 4 5 6 列号 2 4 6 1 3 5 这只是跳

洛谷 P1311 选择客栈 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1311 题目描述 丽江河边有n 家很有特色的客栈,客栈按照其位置顺序从 1 到n 编号.每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k-1 表示),且每家客栈都设有一家咖啡店,每家咖啡店均有各自的最低消费. 两位游客一起去丽江旅游,他们喜欢相同的色调,又想尝试两个不同的客栈,因此决定分别住在色调相同的两家客栈中.晚上,

洛谷 P1855 榨取kkksc03 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1855 题目描述 洛谷的运营组决定,如果一名oier向他的教练推荐洛谷,并能够成功的使用(成功使用的定义是:该团队有20个或以上的成员,上传10道以上的私有题目,布置过一次作业并成功举办过一次公开比赛),那么他可以浪费掉kkksc03的一些时间的同时消耗掉kkksc03的一些金钱以满足自己的一个愿望. Kkksc03的时间和金钱是有限的,