Edge of Taixuan
题意:
给一个n个点的图,和m个区间,每个区间[L, r]中的任意两点都有一条权值为w的边,求删除一些边以后所构成的最小生成树。
题解:
当前[L, r]区间内的点u所连接的线的权值是w,假设多个区间都覆盖到了u这个点那么u所连的线的权值一定是其中wi最小的区间,假设不是这个权值为wi的线,因为当前这个线的作用是就是让u和别的联通,那么其他的一定比wi大,且作用相同,所以选择最小区间是最优的。
所以用线段树来维护一个区间最小值,将m个区间按照权值从大到小排序,靠后的区间直接覆盖靠前的区间即可。最后如果存在一个点的mn为INF则证明没有任何一个区间覆盖住这个点,这个网络就不合法。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <unordered_map>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int n, m, k;
int cnt;
struct Seg {
int l, r;
int mn, lazy;
}tr[N << 2];
struct Node {
int l, r, w;
}e[N];
bool cmp(Node a, Node b) {
return a.w > b.w;
}
LL res, sum;
bool ok;
void down(int u) {
if (tr[u].lazy) {
tr[u << 1].mn = tr[u << 1].lazy = tr[u].lazy;
tr[u << 1 | 1].mn = tr[u << 1 | 1].lazy = tr[u].lazy;
tr[u].lazy = 0;
}
}
void build(int u, int l, int r) {
tr[u] = {l, r, INF, 0};
if (l == r) return ;
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
void modify(int u, int l, int r, int v) {
if (l <= tr[u].l && tr[u].r <= r) {
tr[u].lazy = v;
tr[u].mn = v;
return ;
}
int mid = tr[u].l + tr[u].r >> 1;
down(u);
if (l <= mid) modify(u << 1, l, r, v);
if (r > mid) modify(u << 1 | 1, l, r, v);
}
int query(int u, int pos) {
if (tr[u].l == tr[u].r) return tr[u].mn;
int mid = tr[u].l + tr[u].r >> 1;
down(u);
if (pos <= mid) return query(u << 1, pos);
else return query(u << 1 | 1, pos);
}
int main() {
// ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
res = sum = ok = false;
scanf("%d%d", &n, &m);
build(1, 1, n - 1);
for (int i = 1; i <= m; i ++ ) {
scanf("%d%d%d", &e[i].l, &e[i].r, &e[i].w);
res += 1ll * e[i].w * (e[i].r - e[i].l + 1) * (e[i].r - e[i].l) / 2;
}
sort(e + 1, e + m + 1, cmp);
for (int i = 1; i <= m; i ++ ) modify(1, e[i].l, e[i].r - 1, e[i].w);
for (int i = 1; i < n; i ++ ) {
int val = query(1, i);
if (val == INF) ok = true;
sum += val;
}
printf("Case #%d: ", ++ cnt);
if (ok) printf("Gotta prepare a lesson");
else printf("%ld", res - sum);
if (T) cout << endl;
}
return 0;
}
本文介绍了一种利用线段树维护区间最小值的方法解决特定图论问题——在给定图中寻找最小生成树。通过将区间按权值排序并覆盖的方式优化计算过程,确保了最终结果的正确性和最优性。
445

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



