洛谷P4234 最小差值生成树

news/2024/11/21 1:45:58/

LCT维护生成树

把边从小到大排序,然后一条一条加边,如果成环就把环上最小的删了,我们得到的第一个生成树就是最小生成树。

然后之后每一条边都比前面的生成树的最大边大,我们用这条边的权值减去生成树里最小的,更新答案即可。

因为要维护的是最小值,用排序之后的性质,下表小的值更小来pushup

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define full(a, b) memset(a, b, sizeof a)
#define FAST_IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
using namespace std;
typedef long long LL;
inline int lowbit(int x){ return x & (-x); }
inline int read(){int ret = 0, w = 0; char ch = 0;while(!isdigit(ch)){w |= ch == '-', ch = getchar();}while(isdigit(ch)){ret = (ret << 3) + (ret << 1) + (ch ^ 48);ch = getchar();}return w ? -ret : ret;
}
inline int lcm(int a, int b){ return a / __gcd(a, b) * b; }
template <typename A, typename B, typename C>
inline A fpow(A x, B p, C lyd){A ans = 1;for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd;return ans;
}
const int N = 500005;
int n, m, cnt, tot, cur, ans, val[N], fa[N], ch[N][2], rev[N], id[N], st[N];
bool vis[N];
struct Edge {int u, v, w;bool operator < (const Edge &rhs) const {return w < rhs.w;}
} e[N];int newNode(int x){++ tot;val[tot] = x, id[tot] = tot;rev[tot] = ch[tot][0] = ch[tot][1] = fa[tot] = 0;return tot;
}bool isRoot(int x){return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
}void reverse(int x){rev[x] ^= 1, swap(ch[x][0], ch[x][1]);
}void push_up(int x){id[x] = x;int l = ch[x][0], r = ch[x][1];if(id[l] > n && (id[x] <= n || id[x] > id[l])) id[x] = id[l];if(id[r] > n && (id[x] <= n || id[x] > id[r])) id[x] = id[r];
}void push_down(int x){if(rev[x]){int l = ch[x][0], r = ch[x][1];if(l) reverse(l);if(r) reverse(r);rev[x] ^= 1;}
}void rotate(int x){int y = fa[x], z = fa[y], p = (ch[y][1] == x) ^ 1;ch[y][p^1] = ch[x][p], fa[ch[x][p]] = y;if(!isRoot(y)) ch[z][ch[z][1] == y] = x;fa[x] = z, fa[y] = x, ch[x][p] = y;push_up(y), push_up(x);
}void splay(int x){int pos = 0; st[++pos] = x;for(int i = x; !isRoot(i); i = fa[i]) st[++pos] = fa[i];while(pos) push_down(st[pos--]);while(!isRoot(x)){int y = fa[x], z = fa[y];if(!isRoot(y)){(ch[y][0] == x) ^ (ch[z][0] == y) ? rotate(x) : rotate(y);}rotate(x);}push_up(x);
}void access(int x){for(int p = 0; x; p = x, x = fa[x]){splay(x), ch[x][1] = p, push_up(x);}
}void makeRoot(int x){access(x), splay(x), reverse(x);
}void link(int x, int y){makeRoot(x);fa[x] = y;
}int findRoot(int x){access(x), splay(x);while(ch[x][0]) push_down(x), x = ch[x][0];splay(x);return x;
}void split(int x, int y){makeRoot(x), access(y), splay(y);
}bool isConnect(int x, int y){makeRoot(x);return findRoot(y) == x;
}int main(){n = read(), m = read();for(int i = 1; i <= m; i ++){e[i].u = read(), e[i].v = read(), e[i].w = read();}ans = INF, cur = 1;sort(e + 1, e + m + 1);for(int i = 1; i <= n; i ++) newNode(0);for(int i = 1; i <= m; i ++) newNode(e[i].w);for(int i = 1; i <= m; i ++){int u = e[i].u, v = e[i].v, w = e[i].w;if(u == v) continue;if(!isConnect(u, v)){link(u, i + n), link(i + n, v);vis[i] = true, cnt ++;}else{split(u, v);int tmp = id[v];splay(tmp);fa[ch[tmp][0]] = fa[ch[tmp][1]] = 0;ch[tmp][0] = ch[tmp][1] = 0;vis[tmp - n] = false, vis[i] = true;link(u, i + n), link(i + n, v);while(!vis[cur]) cur ++;}if(cnt == n - 1) ans = min(ans, w - e[cur].w);}cout << ans << endl;return 0;
}

转载于:https://www.cnblogs.com/onionQAQ/p/11232377.html


http://www.ppmy.cn/news/356263.html

相关文章

洛谷 P4234 LCT + 排序 + 枚举

求边权最大值与最小值的差值最小的生成树&#xff0c;输出这个差值大小。 按权值排序&#xff0c;我们等同于枚举最大值&#xff0c;然后更新生成树让生成树的最小值尽可能最大。 也就是每次加入边&#xff0c;若构成环&#xff0c;则去掉环上最小值。 若加入边不会构成环&…

LuoguP4234_最小差值生成树_LCT

LuoguP4234_最小差值生成树_LCT 题意&#xff1a; 给出一个无向图&#xff0c;求最大的边权减最小的边权最小的一棵生成树。 分析&#xff1a; 可以把边权从大到小排序&#xff0c;然后类似魔法森林那样插入。 如果两点不连通&#xff0c;直接连上&#xff0c;否则找到两点间最…

NKOJ 4234 三角分形

问题描述 今天何老板得到了一个神奇的正三角形&#xff0c;它具有自动分形技能。 一天后&#xff0c;它会分成4个相同的正三角形&#xff0c;其中三个“尖尖”朝上&#xff0c;一个“尖尖”朝下。 一天后&#xff0c;里面的每个三角形又会按上述规则分形下去。 如此反复………

[luogu4234]最小差值生成树

[luogu4234]最小差值生成树 luogu 从小到大枚举边,并连接,如果已连通就删掉路径上最小边 lct维护\(ansmin(E_{max}-E_{min})\) #include<bits/stdc.h> using namespace std; const int _4e55; int re(){int x0,w1;char chgetchar();while(ch<0||ch>9){if(ch-)w-1;c…

HDU 4234 Moving Points

刚开始做的时候还以为是暴搜&#xff0c;YY了各种剪枝&#xff0c;结果华丽丽的TLE了 正解&#xff1a; 状态压缩DP dp[当前走到的点][状态] 状态&#xff1a; 第i位表示第i个点有没有被消灭 转移&#xff1a; 详见代码 注意&#xff1a; 计算转移cost时要用O(1) 的算法 二分…

4234最小差值生成树

有点巧妙啊&#xff01; s[x]每次维护的是最小值 我们将边按从大到小排个序,这样编号小的就在前面啦&#xff01;QAQ 再按最小生成树的LCT的做法来 不过我们每次要用一个book标记前面最小边的编号 每次要更新答案时&#xff0c;一直往前跳&#xff0c;跳到最晚更新的即使最小的…

洛谷.4234.最小差值生成树(LCT)

题目链接 先将边排序&#xff0c;这样就可以按从小到大的顺序维护生成树&#xff0c;枚举到一条未连通的边就连上&#xff0c;已连通则(用当前更大的)替换掉路径上最小的边&#xff0c;这样一定不会更差。 每次构成树时更新答案。答案就是当前边减去生成树上最小边的权值。 LCT…

洛谷4234最小差值生成树 (LCT维护生成树)

这也是一道LCT维护生成树的题。 那么我们还是按照套路&#xff0c;先对边进行排序&#xff0c;然后顺次加入。 不过和别的题有所不同的是&#xff1a; 在本题中&#xff0c;我们需要保证LCT中正好有\(n-1\)条边的时候&#xff0c;才能更新\(ans\) 其次&#xff0c;更新答案的时…