Brief description

给定一个无向图,求从1到n的一条路径使得这条路径上最大的a和b最小。

Algorithm Design

以下内容选自某HN神犇的blog

双瓶颈的最小生成树的感觉,可以首先按a值排序,然后一条边一条边的加入.

  如果之前连接的两点还未连通,那么连上先满足最后连通性的必要.

  如果之前连接的两点已经连通,那么就在原来的路径上找到一条b值最大的,然后删掉原来的,加上现在的边,保证最优性的需要.

  这样会导致最大的b值的减小,但是如果之前1,n已经连通,也会造成最大的a值的增大

  [因为是按a排序,在连通前的操作都是不管a值的,只以最后一次加的边为最大[所以之前的替换操作只会让这个路径更优],但是连通后,添加的边就会让a值增大[不一定会更优]],这就需要在多种方案间选出最优.

  上面说得很轻巧,现在我们想想怎么完成上述操作.

  总共要对每条边处理一次,每次需要连边或者在两点之前的链上找最大值.找到之后有删边的操作.

  支持这么多操作的数据结构有什么?[注意我们连接的一定是一棵树[或是一片森林]...不然就浪费了...]

  lca似乎不兹瓷啊,因为是动态的,哦,那就是动态树了.

  动态树中带边权的怎么处理呢?可以将所有实点的值定为0,连(u,v)边改为连(u,x)和(x,v),x的值代表这条边的边权.

  [p.s]有的同学会觉得我连(u,v)把值记在u上或者v上就可以了...每次splay的时候,只有根节点保留的是在原树中连接上个部分的边权,其它的在splay的时候交换.[<-这一步是可以实现的]

    有的同学觉得我这样不就可以了么?然而...你还有个东西叫Access(),你每次会将原来本来是链的顶部才能连的边,给了当前splay的根,然后连通之后再splay,鬼才找的到原来的边是什么?..当然上面的"有的同学"都是说的笔者..有的大神说不定还是可以不加虚拟边点过的...

Code

#include <algorithm>
#include <cstdio>
int n, m;
const int maxn = 50010;
const int maxm = 100010;
const int maxv = maxn + maxm;
struct edge {
int u, v, a, b;
} e[maxm << 1];
bool cmp1(edge a, edge b) { return a.a < b.a; }
int f[maxn], val[maxv], fa[maxv], ch[maxv][2], rev[maxv], max[maxv];
int findf(int x) { return f[x] == x ? x : f[x] = findf(f[x]); }
void pushdown(int x) {
if (rev[x]) {
rev[x] ^= 1;
rev[ch[x][0]] ^= 1;
rev[ch[x][1]] ^= 1;
std::swap(ch[x][0], ch[x][1]);
}
}
void update(int x) {
max[x] = x;
if (val[max[ch[x][0]]] > val[max[x]])
max[x] = max[ch[x][0]];
if (val[max[ch[x][1]]] > val[max[x]])
max[x] = max[ch[x][1]];
}
bool isroot(int x) { return (ch[fa[x]][0] != x) && (ch[fa[x]][1] != x); }
void zig(int x) {
int y = fa[x], z = fa[y], l = (ch[y][1] == x), r = l ^ 1;
if (!isroot(y))
ch[z][ch[z][1] == y] = x;
fa[ch[y][l] = ch[x][r]] = y;
fa[ch[x][r] = y] = x;
fa[x] = z;
update(y);
update(x);
}
void splay(int x) {
int s[maxv], top = 0;
s[++top] = x;
for (int i = x; !isroot(i); i = fa[i])
s[++top] = fa[i];
while (top)
pushdown(s[top--]);
for (int y; !isroot(x); zig(x))
if (!isroot(y = fa[x]))
zig((ch[y][0] == x) == (ch[fa[y]][0] == y) ? y : x);
update(x);
}
void access(int x) {
for (int t = 0; x; t = x, x = fa[x]) {
splay(x);
ch[x][1] = t;
update(x);
}
}
void makeroot(int x) {
access(x);
splay(x);
rev[x] ^= 1;
}
void link(int x, int y) {
makeroot(x);
fa[x] = y;
}
void cut(int x, int y) {
makeroot(x);
access(y);
splay(y);
ch[y][0] = fa[x] = 0;
update(y);
}
void split(int x, int y) {
makeroot(y);
access(x);
splay(x);
}
int ans = 0x3f3f3f;
int main() {
freopen("input", "r", stdin);
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
f[i] = i;
for (int i = 1; i <= m; i++) {
scanf("%d %d %d %d", &e[i].u, &e[i].v, &e[i].a, &e[i].b);
}
std::sort(e + 1, e + 1 + m, cmp1);
for (int i = 1; i <= m; i++) {
int u = e[i].u, v = e[i].v, x = findf(u), y = findf(v);
if (x == y) {
split(u, v);
int t = max[u];
if (val[t] > e[i].b) {
cut(e[t - n].u, t);
cut(e[t - n].v, t);
} else {
if (findf(1) == findf(n)) {
split(1, n);
int t = max[1];
ans = std::min(ans, e[i].a + val[t]);
}
continue;
}
}
if (x != y) {
f[x] = y;
}
val[n + i] = e[i].b;
max[n + i] = n + i;
link(u, i + n);
link(v, i + n);
if (findf(1) == findf(n)) {
split(1, n);
int t = max[1];
ans = std::min(ans, e[i].a + val[t]);
}
}
printf("%d\n", ans == 0x3f3f3f ? -1 : ans);
}

[bzoj3669][Noi2014]魔法森林——lct的更多相关文章

  1. bzoj3669: [Noi2014]魔法森林 lct版

    先上题目 bzoj3669: [Noi2014]魔法森林 这道题首先每一条边都有一个a,b 我们按a从小到大排序 每次将一条路劲入队 当然这道题权在边上 所以我们将边化为点去连接他的两个端点 当然某两 ...

  2. bzoj3669: [Noi2014]魔法森林 lct

    记得去年模拟赛的时候好像YY出二分答案枚举a,b的暴力,过了55欸 然后看正解,为了将两维变成一维,将a排序,模拟Kruskal的加边过程,同时维护1到n的最大值,加入一条边e(u,v,a,b)时有以 ...

  3. BZOJ 3669: [Noi2014]魔法森林( LCT )

    排序搞掉一维, 然后就用LCT维护加边MST. O(NlogN) ------------------------------------------------------------------- ...

  4. bzoj 3669: [Noi2014]魔法森林 (LCT)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3669 题面: 3669: [Noi2014]魔法森林 Time Limit: 30 Sec  ...

  5. [NOI2014]魔法森林 LCT

    题面 [NOI2014]魔法森林 题解 一条路径的代价为路径上的\(max(a[i]) + max(b[i])\),因为一条边同时有$a[i], b[i]$2种权值,直接处理不好同时兼顾到,所以我们考 ...

  6. loj2245 [NOI2014]魔法森林 LCT

    [NOI2014]魔法森林 链接 loj 思路 a排序,b做动态最小生成树. 把边拆成点就可以了. uoj98.也许lct复杂度写假了..越卡常,越慢 代码 #include <bits/std ...

  7. 【BZOJ3669】[Noi2014]魔法森林 LCT

    终于不是裸的LCT了...然而一开始一眼看上去这是kruskal..不对,题目要求1->n的路径上的每个点的两个最大权值和最小,这样便可以用LCT来维护一个最小生成路(瞎编的...),先以a为关 ...

  8. BZOJ3669[Noi2014]魔法森林——kruskal+LCT

    题目描述 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节点1,隐士则住 ...

  9. BZOJ3669: [Noi2014]魔法森林(瓶颈生成树 LCT)

    Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 3558  Solved: 2283[Submit][Status][Discuss] Descript ...

随机推荐

  1. IOException: win32 io returned 267. Path:

    unity3d在导出android项目时出现了这个错误,找了一圈也没找到原因,最后把项目名中空格去掉后OK了,坑啊!!!!

  2. Python第三方库之openpyxl(3)

    Python第三方库之openpyxl(3) 区域图 区域图类似于折线图,绘图线下面的区域会被填充,通过将分组设置为“standard”.“stacked”或“percentStacked”,可以获得 ...

  3. 8.0 TochAction各种用法

    1.滑动---TouchAction  支持相对坐标.绝对坐标.Element 注意看顶部的导入TouchAction这个库.. #实例化 action = TouchAction(driver) # ...

  4. json与python解析

    1.json.dumps     将 Python 对象编码成 JSON 字符串   json.loads      将已编码的 JSON 字符串解码为 Python 对象 2.json.dump() ...

  5. zabbix 通过key(键值)获取信息

    在agent端进行修改264行,例如: UserParameter=get.os.type,head -1 /etc/issue 保存重启agent 验证 zabbix_get -s IP -k ge ...

  6. Selenium Grid 环境搭建 碰到的unable to access server

    1. Slenenium Grid的环境部署, 前提条件: JDK,JRE都已经安装, selenium的standalone jar包放在磁盘 执行如下命令,报错: 2. 在cmd窗口里切换到jar ...

  7. HDU 4582 DFS spanning tree(DFS+贪心)(2013ACM-ICPC杭州赛区全国邀请赛)

    Problem Description Consider a Depth-First-Search(DFS) spanning tree T of a undirected connected gra ...

  8. 学习bash——通配符与特殊符号

    一.通配符 这是bash操作环境中一个非常有用的功能,这让我们使用bash处理数据就更方便了. 常用通配符如下: 符号 意义 * 代表0个到无穷多个任意字符 ? 代表一个任意字符 [] 代表一定有一个 ...

  9. BZOJ1559 [JSOI2009]密码 【AC自动机 + 状压dp】

    题目链接 BZOJ1559 题解 考虑到这是一个包含子串的问题,而且子串非常少,我们考虑\(AC\)自动机上的状压\(dp\) 设\(f[i][j][s]\)表示长度为\(i\)的串,匹配到了\(AC ...

  10. POJ 开关问题 解题报告

    开关问题 Time Limit: 1000MS Memory Limit: 30000K Description 有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他 ...