传送门

这道题,先用kruskal求一遍图中的最大生成树。

然后,倍增求lca,求lca的同时求出边权的最小值。

#include <cstring>
#include <cstdio>
#include <algorithm> int n, m, cnt, q, t, k;
int f[], head[], p[][], minn[][], deep[];
bool vis[];
struct node
{
int x, y, z;
}tree[];
struct Node
{
int next, to, val;
}edge[]; inline void add(int a, int b, int c)
{
edge[cnt].val = c;
edge[cnt].to = b;
edge[cnt].next = head[a];
head[a] = cnt++;
} inline int father(int a)
{
return a == f[a] ? a : f[a] = father(f[a]);
} inline bool cmp(node a, node b)
{
return a.z > b.z;
} void kruskal()
{
int i;
for(i = ; i <= m; i++) scanf("%d %d %d", &tree[i].x, &tree[i].y, &tree[i].z);
for(i = ; i <= n; i++) f[i] = i;
std::sort(tree + , tree + m + , cmp);
for(i = ; i <= m; i++)
{
int fa = father(tree[i].x), fb = father(tree[i].y);
if(fa != fb)
{
f[fa] = fb;
add(tree[i].x, tree[i].y, tree[i].z);
add(tree[i].y, tree[i].x, tree[i].z);
}
if(k == n - ) break;
}
} void dfs(int i)
{
int j;
vis[i] = ;
for(j = head[i]; j != -; j = edge[j].next)
if(!vis[edge[j].to])
{
deep[edge[j].to] = deep[i] + ;
p[edge[j].to][] = i;
minn[edge[j].to][] = edge[j].val;
dfs(edge[j].to);
}
} void init()
{
int i, j;
for(j = ; ( << j) <= n; j++)
for(i = ; i <= n; i++)
{
p[i][j] = p[p[i][j - ]][j - ];
minn[i][j] = std::min(minn[i][j - ], minn[p[i][j - ]][j - ]);
}
} int lca(int a, int b)
{
int i, j, ret = ;
if(deep[a] < deep[b]) std::swap(a, b);
for(i = ; ( << i) <= deep[a]; i++);
i--;
for(j = i; j >= ; j--)
if(deep[a] - ( << j) >= deep[b])
{
ret = std::min(ret, minn[a][j]);
a = p[a][j];
}
if(a == b) return ret;
for(j = i; j >= ; j--)
if(p[a][j] != p[b][j])
{
ret = std::min(ret, std::min(minn[a][j], minn[b][j]));
a = p[a][j];
b = p[b][j];
}
ret = std::min(ret, std::min(minn[a][], minn[b][]));
return ret;
} int main()
{
int i, j, x1, y1;
scanf("%d %d", &n, &m);
memset(head, -, sizeof(head));
//memset(minn, 127 / 3, sizeof(minn));
kruskal();
for(i = ; i <= n; i++)
if(!vis[i])
{
deep[i] = ;
dfs(i);
}
init();
scanf("%d", &q);
for(i = ; i <= q; i++)
{
scanf("%d %d", &x1, &y1);
if(father(x1) != father(y1)) printf("-1\n");
else printf("%d\n", lca(x1, y1));
}
return ; }

换了写法

惨啊,

i >= 0 我居然nc的用 i 代替

应该是 i >= 1 用 i 代替

 #include <cstdio>
#include <cstring>
#include <algorithm> const int MAXN = , MAXM = , INF = ;
int n, m, q, cnt, tot;
int head[MAXM], to[MAXM << ], next[MAXM << ], val[MAXM << ];
int f1[MAXN], f[MAXN][], min[MAXN][], deep[MAXN]; struct node
{
int x, y, z;
}p[MAXM]; inline bool cmp(node a, node b)
{
return a.z > b.z;
} inline void add(int x, int y, int z)
{
to[cnt] = y;
val[cnt] = z;
next[cnt] = head[x];
head[x] = cnt++;
} inline int find(int x)
{
return x == f1[x] ? x : f1[x] = find(f1[x]);
} inline int Min(int x, int y)
{
return x < y ? x : y;
} inline void swap(int &x, int &y)
{
x ^= y ^= x ^= y;
} inline void dfs(int u)
{
int i, v;
deep[u] = deep[f[u][]] + ;
for(i = ; f[u][i]; i++)
f[u][i + ] = f[f[u][i]][i],
min[u][i + ] = Min(min[u][i], min[f[u][i]][i]);
for(i = head[u]; i ^ -; i = next[i])
{
v = to[i];
if(!deep[v])
{
f[v][] = u;
min[v][] = val[i];
dfs(v);
}
}
} inline int lca(int x, int y)
{
int i, ans = INF;
if(deep[x] < deep[y]) swap(x, y);
for(i = ; i >= ; i--)
if(deep[f[x][i]] >= deep[y])
ans = Min(ans, min[x][i]), x = f[x][i];
if(x == y) return ans == INF ? - : ans;
for(i = ; i >= ; i--)
if(f[x][i] ^ f[y][i])
ans = Min(ans, min[x][i]),
ans = Min(ans, min[y][i]),
x = f[x][i], y = f[y][i];
ans = Min(ans, min[x][]);
ans = Min(ans, min[y][]);
return ans == INF ? - : ans;
} int main()
{
//freopen("truck.in", "r", stdin);
//freopen("truck.out", "w", stdout);
int i, x, y, fx, fy;
scanf("%d %d", &n, &m);
memset(head, -, sizeof(head));
memset(min, / , sizeof(min));
for(i = ; i <= m; i++) scanf("%d %d %d", &p[i].x, &p[i].y, &p[i].z);
std::sort(p + , p + m + , cmp);
for(i = ; i <= n; i++) f1[i] = i;
for(i = ; i <= m; i++)
{
fx = find(p[i].x);
fy = find(p[i].y);
if(fx ^ fy)
{
f1[fx] = fy;
tot++;
add(p[i].x, p[i].y, p[i].z);
add(p[i].y, p[i].x, p[i].z);
}
if(tot == n - ) break;
}
for(i = ; i <= n; i++)
if(!deep[i])
dfs(i);
scanf("%d", &q);
for(i = ; i <= q; i++)
{
scanf("%d %d", &x, &y);
if(find(x) ^ find(y)) puts("-1");
else printf("%d\n", lca(x, y));
}
return ;
}

NOIP2013D1T3货车运输(最大生成树+倍增lca)的更多相关文章

  1. TZOJ 4848 货车运输(最大生成树+倍增lca)

    描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多 ...

  2. $Noip2013/Luogu1967$ 货车运输 最大生成树+倍增$lca$

    $Luogu$ $Sol$ 首先当然是构建一棵最大生成树,然后对于一辆货车的起点和终点倍增跑$lca$更新答案就好.记得预处理倍增的时候不仅要处理走了$2^i$步后是那个点,还有这中间经过的路径权值的 ...

  3. 【NOIP2013】货车运输 最大生成树+倍增

    题目大意:给你一张n个点m条边的图,有q次询问,每次让你找出一条从x至y的路径,使得路径上经过的边的最小值最大,输出这个最大的最小值. 显然,经过的路径必然在这张图的最大生成树上. 我们求出这个图的最 ...

  4. 「NOIP2013」「LuoguP1967」货车运输(最大生成树 倍增 LCA

    题目描述 AA国有nn座城市,编号从 11到nn,城市之间有 mm 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最 ...

  5. 货车运输(最大生成树+倍增LCA)

    看到第一篇题解的神奇码风--我决定发一篇码风正常的题解造福人类 这题的做法也非常经典,最大生成树\(+LCA\),相当于先贪心一下,在LCA的时候记录一下当前最小的边权 顺便吐槽一下最后一个测试点: ...

  6. 【洛谷1967】货车运输(最大生成树+倍增LCA)

    点此看题面 大致题意: 有\(n\)个城市和\(m\)条道路,每条道路有一个限重.多组询问,每次询问从\(x\)到\(y\)的最大载重为多少. 一个贪心的想法 首先,让我们来贪心一波. 由于要求最大载 ...

  7. 货车运输 noip2013 luogu P1967 (最大生成树+倍增LCA)

    luogu题目传送门! 首先,题目让我们求每个货车的最大运输量,翻译一下就是求路径上边权最小的边. 利用一下贪心思想可知,所有货车肯定都会尽量往大的边走. 进一步翻译,即为有一些小边货车根本不会走,或 ...

  8. 【NOIP2013】货车运输 最大生成树+LCA

    题目描述 AA国有nn座城市,编号从 1到n,城市之间有m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重 ...

  9. Luogu1967 NOIP2013 货车运输 最大生成树、倍增

    传送门 题意:给出一个$N$个节点.$M$条边的图,$Q$次询问,每一次询问两个点之间的所有可行路径中经过的边的边权的最小值中的最大值.$N \leq 10000 , M \leq 50000 , Q ...

随机推荐

  1. page.php 引入js文件

    2种写法 <script type='text/javascript' src='<?php echo get_template_directory_uri().'/js/jquery-1 ...

  2. grunt配置详情

    这个grunt配置 是我的一个程序员朋友从网上无意间看到的,然后他亲测了下,恩,是可以的.不过我到目前还未测试过是否可以. 一.安装node, 首先确保电脑已有node的环境.然后 运行  npm i ...

  3. 利用伪类写一个自定义checkbox和radio

    首先是效果图来一张 再来一张html结构 关键的CSS来了~ 首先呢要把input标签设置为display: none;  因为自定义的原理是通过label的for属性,来点击label转向为点击in ...

  4. 千万千万不要运行的 Linux 命令

    文中列出的命令绝对不可以运行,即使你觉得很好奇也不行,除非你是在虚拟机上运行(出现问题你可以还原),因为它们会实实在在的破坏你的系统.所以不在root等高级管理权限下执行命令是很好的习惯. 早晚有一天 ...

  5. TCP和流

    http://www.cnblogs.com/lwzz/archive/2011/07/03/2096963.html TCP是一种流协议(stream protocol).这就意味着数据是以字节流的 ...

  6. JS concat() 方法

    [数组元素的合并] 一. concat() 方法 concat() 方法用于连接两个或多个数组. 返回一个新的数组.该数组是通过把所有 arrayX 参数添加到 arrayObject 中生成的.如果 ...

  7. nginx 的编译安装及基本操作

    下载nginx [root@nginx ~]# wget http://nginx.org/download/nginx-1.14.0.tar.gz --2019-05-02 21:52:23-- h ...

  8. Java数据结构和算法(二)--队列

    上一篇文章写了栈的相关知识,而本文会讲一下队列 队列是一种特殊的线性表,在尾部插入(入队Enqueue),从头部删除(出队Dequeue),和栈的特性相反,存取数据特点是:FIFO Java中queu ...

  9. Xcode导入第三方库

    Xcode导入第三方库,例如TapkuLibrary iOS开源框架Tapku下载地址:https://github.com/devinross/tapkulibrary.git 1.创建你的工程项目 ...

  10. 函数内部属性之arguments和this

    在函数内部,有两个特殊的对象:arguments和this. 1.arguments arguments是一个类数组对象.包含着传入函数中的所有参数.但这个对象还有一个名叫callee的属性,该属性是 ...