题目描述
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。
输入输出样例
4 3 1 2 4 2 3 3 3 1 1 3 1 3 1 4 1 3
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。
蒟蒻一眼还是不会写的。。。。。
百度了一下题解:
先用kruscal对每一个联通块建一棵最大生成树,
事实上就可以发现每个询问(u,v)就是回答最大生成树上u,v两点间路径的最小边权值
于是想到树剖。
关于这个为什么询问就是回答这个答案
蒟蒻给出一个比较合(xia)理(che)的解释:
假设u,v两点间还有一条路径,该路径上的最小边权值大于最大生成树上路径的最小边权值
那么在建最大生成树上时,该最小边一定被包括在树中
于是可以得到这样的结论
据说是裸题。。?我真菜啊。。。
upd.2017.10.27 用LCT写起来贼爽
代码:
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int max_n = 10100;
const int max_m = 50100;
const int max_seg = 4 * max_m;
const int INF = 2147483647;
struct data{
int u,v,w;
}edge[max_m],mst_edge[max_n],scc_edge[max_m];
struct Data{
int to,w;
}e[2 * max_m];
vector<int> _G[max_n]; //原图
vector<int> G[max_n]; //最大生成树森林
int wedge[max_seg],minx[max_seg],tot; //线段树相关
int fa[max_n],faedge[max_n],sonw[max_n],son[max_n],top[max_n],dep[max_n],siz[max_n]; //树剖相关
int father[max_n]; //并查集相关
bool vis[max_n],vis_m[max_m]; //连通相关
int n,m,q,tot_e,cnt_e,tot_G,cnt_p; //tot_e == scc_edge,cnt_e == mst_edge,tot_G == e
inline int getint()
{
int ret = 0;
char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9')
ret = ret * 10 + c - '0',c = getchar();
return ret;
}
inline bool cmp(data a,data b)
{
return a.w > b.w;
}
inline int find(int x)
{
if (father[x] != x)
{
int ret = find(father[x]);
father[x] = ret;
return ret;
}
else return x;
}
inline void init(int o,int f,int depth)
{
fa[o] = f;
dep[o] = depth;
for (int i = 0; i < G[o].size(); i++)
{
int v = e[G[o][i]].to,w = e[G[o][i]].w;
if (v == f) continue;
init(v,o,depth + 1);
if (siz[v] > siz[son[o]])
{
son[o] = v;
sonw[o] = w;
}
siz[o] += siz[v];
}
siz[o]++;
}
inline void cut(int o,int f)
{
if (G[o].size() == 1 && e[G[o][0]].to == f) return;
top[son[o]] = top[o];
faedge[son[o]] = ++tot;
wedge[tot] = sonw[o];
cut(son[o],o);
for (int i = 0; i < G[o].size(); i++)
{
int v = e[G[o][i]].to,w = e[G[o][i]].w;
if (v == f || v == son[o]) continue;
faedge[v] = ++tot;
wedge[tot] = w;
top[v] = v;
cut(v,o);
}
}
inline void build(int o,int l,int r)
{
if (l == r)
{
minx[o] = wedge[l];
return;
}
int mid = l + r >> 1,lc = o * 2,rc = o * 2 + 1;
build(lc,l,mid);
build(rc,mid + 1,r);
minx[o] = min(minx[lc],minx[rc]);
}
inline int query(int o,int l,int r,int al,int ar)
{
if (al <= l && r <= ar) return minx[o];
int mid = l + r >> 1,lc = o * 2,rc = o * 2 + 1;
if (ar <= mid) return query(lc,l,mid,al,ar);
if (al >= mid + 1) return query(rc,mid + 1,r,al,ar);
return min(query(lc,l,mid,al,ar),query(rc,mid + 1,r,al,ar));
}
inline int path_query(int u,int v)
{
int f1 = top[u],f2 = top[v],ans = INF;
while (f1 != f2)
{
if (dep[f1] < dep[f2]) {swap(f1,f2); swap(u,v);}
ans = min(ans,query(1,1,tot,faedge[f1],faedge[u]));
u = fa[f1];
f1 = top[u];
}
if (u == v) return ans;
if (dep[u] > dep[v]) swap(u,v);
return min(ans,query(1,1,tot,faedge[son[u]],faedge[v]));
}
inline void dfs(int u)
{
vis[u] = 1;
cnt_p++;
for (int i = 0; i < _G[u].size(); i++)
{
int v = (edge[_G[u][i]].u == u ? edge[_G[u][i]].v : edge[_G[u][i]].u);
if (!vis_m[_G[u][i]])
{
scc_edge[++tot_e] = edge[_G[u][i]];
vis_m[_G[u][i]] = 1;
}
if (!vis[v])
dfs(v);
}
}
int main()
{
n = getint(); m = getint();
for (int i = 1; i <= m; i++)
{
int u = getint(),v = getint(),w = getint();
edge[i] = (data){u,v,w};
_G[u].push_back(i);
_G[v].push_back(i);
}
for (int i = 1; i <= n; i++)
father[i] = i;
for (int j = 1; j <= n; j++)
if (!vis[j])
{
cnt_p = 0;
dfs(j);
if (cnt_p == 1) continue;
sort(scc_edge + 1,scc_edge + tot_e + 1,cmp);
cnt_e = 0;
for (int i = 1; i <= tot_e; i++)
{
if (cnt_e == cnt_p - 1) break;
int u = scc_edge[i].u,v = scc_edge[i].v;
if (find(u) != find(v))
{
mst_edge[++cnt_e] = scc_edge[i];
father[find(v)] = find(u);
}
}
tot_e = 0;
for (int i = 1; i <= cnt_p - 1; i++)
{
int u = mst_edge[i].u,v = mst_edge[i].v,w = mst_edge[i].w;
e[++tot_G] = (Data){v,w};
G[u].push_back(tot_G);
e[++tot_G] = (Data){u,w};
G[v].push_back(tot_G);
}
init(j,0,1);
top[j] = j;
cut(j,0);
}
build(1,1,tot);
q = getint();
for (int i = 1; i <= q; i++)
{
int u = getint(),v = getint();
if (find(u) != find(v)) printf("-1\n");
else printf("%d\n",path_query(u,v));
}
return 0;
}

本文介绍了一道关于货车运输的问题,通过构建最大生成树并运用树剖算法解决货车的最大载重问题。讨论了如何利用kruskal算法构建最大生成树,并详细解释了树剖算法的具体实现。

1287

被折叠的 条评论
为什么被折叠?



