首页 > 其他分享 >GDCPC2023 L Classic Problem

GDCPC2023 L Classic Problem

时间:2023-10-13 17:25:18浏览次数:40  
标签:typedef Classic int GDCPC2023 ll maxn 定边 Problem find

洛谷传送门

CF 传送门

对于一个点 \(x\),若 \(\exists i, u_i = x \lor v_i = x\),则称 \(x\) 为特殊点,否则为一般点

首先发现,对于极长的一段 \([l, r]\) 满足 \(l \sim r\) 均为一般点,那么可以连边 \((l, l + 1), (l + 1, l + 2), \ldots, (r - 1, r)\),然后把 \([l, r]\) 缩成一个连续点。因为这些点通过别的点与外界连通显然不优。

对于一个特殊点 \(x\),我们把它变成区间为 \([x, x]\) 的连续点。然后把所有连续点按区间左端点排序后重编号。

然后现在相当于我们有至多 \(4m + 1\) 个点的完全图,有一些给定边,若对于之间不存在给定边的点对 \(u, v\ (u < v)\),它们之间的边权是 \(l_v - r_u\)。求这个完全图的最小生成树。

考虑 Boruvka 算法,其流程是每轮对每个连通块找到一条连向另一连通块的最短边,然后合并两端点。

考虑模拟流程。我们首先考虑给定边,然后考虑其他边。前者是容易的。至于后者,我们希望找到 \(u\) 左右侧最接近 \(u\) 且和 \(u\) 不在同一连通块且和 \(u\) 之间没有给定边的点 \(v\)。于是我们每次先处理出 \(pre_u\) 和 \(nxt_u\) 表示 \(u\) 左侧(或右侧)最接近 \(u\) 且和 \(u\) 不在同一连通块的点,然后枚举 \(u\),暴力找 \(v\),以左侧为例,就是若 \(u, v\) 之间存在给定边就 \(v \gets v - 1\),否则 \(v \gets pre_v\)。因为给定边数量是 \(O(m)\) 的,所以这部分复杂度是对的。

若使用 set 存给定边,时间复杂度为 \(O(m \log^2 m)\)。

code
// Problem: P9701 [GDCPC2023] Classic Problem
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P9701
// Memory Limit: 1 MB
// Time Limit: 8000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 500100;

ll n, m, lsh[maxn], tot, fa[maxn], pre[maxn], nxt[maxn];
pii f[maxn];
set<ll> S[maxn];

struct E {
	ll u, v, d;
	E(ll a = 0, ll b = 0, ll c = 0) : u(a), v(b), d(c) {}
} Es[maxn], G[maxn];

int find(int x) {
	return fa[x] == x ? x : fa[x] = find(fa[x]);
}

inline bool merge(int x, int y) {
	x = find(x);
	y = find(y);
	if (x != y) {
		fa[x] = y;
		return 1;
	} else {
		return 0;
	}
}

struct node {
	ll l, r, f;
	node(ll a = 0, ll b = 0, ll c = 0) : l(a), r(b), f(c) {}
} a[maxn];

inline bool operator < (const node &a, const node &b) {
	return a.l < b.l;
}

void solve() {
	scanf("%lld%lld", &n, &m);
	for (int i = 1; i <= m * 5; ++i) {
		S[i].clear();
	}
	tot = 0;
	for (int i = 1; i <= m; ++i) {
		scanf("%lld%lld%lld", &Es[i].u, &Es[i].v, &Es[i].d);
		lsh[++tot] = Es[i].u;
		lsh[++tot] = Es[i].v;
	}
	sort(lsh + 1, lsh + tot + 1);
	tot = unique(lsh + 1, lsh + tot + 1) - lsh - 1;
	lsh[0] = 0;
	lsh[tot + 1] = n + 1;
	ll K = tot, ans = 0;
	for (int i = 1; i <= tot; ++i) {
		a[i] = node(lsh[i], lsh[i], 1);
	}
	for (int i = 0; i <= tot; ++i) {
		if (lsh[i] + 1 != lsh[i + 1]) {
			a[++K] = node(lsh[i] + 1, lsh[i + 1] - 1, 0);
			ans += lsh[i + 1] - lsh[i] - 2;
		}
	}
	sort(a + 1, a + K + 1);
	int tt = 0;
	map<pii, ll> mp;
	for (int i = 1; i <= m; ++i) {
		ll u = Es[i].u, v = Es[i].v, d = Es[i].d;
		u = lower_bound(a + 1, a + K + 1, node(u, u, 0)) - a;
		v = lower_bound(a + 1, a + K + 1, node(v, v, 0)) - a;
		if (u > v) {
			swap(u, v);
		}
		G[++tt] = E(u, v, d);
		S[u].insert(v);
		S[v].insert(u);
		mp[mkp(u, v)] = mp[mkp(v, u)] = d;
	}
	for (int i = 1; i <= K; ++i) {
		fa[i] = i;
	}
	while (1) {
		bool flag = 1;
		for (int i = 1; i <= K; ++i) {
			if (find(i) != find(1)) {
				flag = 0;
				break;
			}
		}
		if (flag) {
			break;
		}
		for (int i = 1; i <= K; ++i) {
			f[i] = mkp(1e18, -1);
		}
		for (int u = 1; u <= K; ++u) {
			for (int v : S[u]) {
				if (find(u) == find(v)) {
					continue;
				}
				ll d = mp[mkp(u, v)];
				f[find(u)] = min(f[find(u)], mkp(d, 1LL * find(v)));
			}
		}
		for (int i = 1, j = 1; i <= K; i = (++j)) {
			while (j < K && find(j + 1) == find(i)) {
				++j;
			}
			for (int u = i; u <= j; ++u) {
				pre[u] = i - 1;
				nxt[u] = j + 1;
			}
		}
		for (int u = 1; u <= K; ++u) {
			int v = u;
			while (v >= 1 && (S[u].find(v) != S[u].end() || find(v) == find(u))) {
				if (find(v) == find(u)) {
					v = pre[v];
				} else {
					--v;
				}
			}
			if (v) {
				f[find(u)] = min(f[find(u)], mkp(a[u].l - a[v].r, 1LL * find(v)));
			}
			v = u;
			while (v <= K && (S[u].find(v) != S[u].end() || find(v) == find(u))) {
				if (find(v) == find(u)) {
					v = nxt[v];
				} else {
					++v;
				}
			}
			if (v <= K) {
				f[find(u)] = min(f[find(u)], mkp(a[v].l - a[u].r, 1LL * find(v)));
			}
		}
		for (int i = 1; i <= K; ++i) {
			if (fa[i] == i && merge(i, f[i].scd)) {
				ans += f[i].fst;
			}
		}
	}
	printf("%lld\n", ans);
}

int main() {
	int T = 1;
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:typedef,Classic,int,GDCPC2023,ll,maxn,定边,Problem,find
From: https://www.cnblogs.com/zltzlt-blog/p/17762608.html

相关文章

  • 2024版Lightroom Classic13.0版本免激活版更新及资源
    2023年10月10日,Adobe又更新了LightroomClassic,当前最新的版本为13.0版本,本次更新最重磅的功能是使用人工智能AI来处理以前需要昂贵的镜头才能出来的模糊效果。LightroomClassic13.0版本使用了人工智能驱动的镜头模糊模糊背景或前景,轻松增加图像的深度。无需投资昂贵的镜头即可实......
  • tp5 php 阿里OS RequestCoreException: cURL error: SSL certificate problem: certif
    出现这种情况,肯定是域名SSL证书过期。现在出现问题:提交表单出现这种情况,网址不是https的,之前一直也没有问题,一开始想不通网址都不是HTTPS为什么还会有SSL证书的问题,检查了下发现上传中图片是上传到阿里OSS的(https://img.oss.xxx.com),里边就用到了HTTPS域名,原来是这样里,一查发现过......
  • [CF1285F]Classical?
    F-Classical?考虑先加上\(gcd(a_i,a_j)=1\)的限制从大到小扫集合里的数,若扫到数\(x\)发现存在\(y>x\)且\(gcd(x,y)=1\),则所有\(x<t<y\)的\(t\)都不会再对答案有贡献了,因此使用栈存储扫过的元素,当扫到\(x\)时,只要栈中有与\(x\)互质的数就弹栈,并与\(x\)更新答案那么如何快速判......
  • 题解 CF457F 【An easy problem about trees】
    尝试理解,感谢cz_xuyixuan的题解。算作是很多情况的补充说明。我们不妨先二分答案,将\(\gemid\)的设为\(1\),\(<mid\)的设为\(0\),于是问题转化为了权值均为\(0/1\)的版本。我们称一棵树的大小为其非叶节点数。我们称一棵大小为奇数的树为奇树,大小为偶数的树为偶树。对......
  • 2023-02-06Fix dual system time problem copy
    +++title="Fixdualsystemtimeproblem"description=""date=2023-02-06T14:21:50+08:00featured=falsecomment=truetoc=truereward=truecategories=[""]tags=["ubuntu"]series=[]images=[]+......
  • 题解 AGC015D【A or...or B Problem】
    题解AGC015D【Aor...orBProblem】problem从\(\geA\)且\(\leB\)的整数中选择一个或多个,把这些整数按位或,求一共有多少种可能的结果。\(1\leA\leB\le2^{60}\)solution首先暴力怎么写呢?FWT。设序列\(a_i=[L\leqi\leqR]\),然后对它FWT-or之后自己乘几倍,再翻回......
  • 题解 P9701【[GDCPC2023] Classic Problem】
    题如其名,确实挺经典的。我们称边权在输入中给定的边为特殊边,其它边为平凡边。称特殊边涉及到的点为特殊点,其它点为平凡点。显然,对于连续的若干平凡点\([l,r]\),他们内部的最优连边方式就是连成一条链,花费\(r-l\)的代价。我们先把这样的代价加到答案中,然后将极长连续平凡点缩成......
  • 题解 P9695【[GDCPC2023] Traveling in Cells】
    显然,询问的答案即为\(x\)所在的极长的满足颜色均在\(\mathbb{A}\)内的连续段的权值和。如果我们能维护对颜色的单点修改,以及求出某个位置所在极长连续段的左右端点\(l,r\),只需要树状数组即可求出答案。一个朴素的想法是对每种颜色开一棵线段树,单点修改是平凡的,极长连续段左......
  • 题解 P9702【[GDCPC2023] Computational Geometry】
    这题一看就不是计算几何,考虑区间DP。设凸多边形的\(n\)个顶点依次为\(P_1,P_2,\cdots,P_n\)。设\(f_{i,j}\)在\(i<j\)时表示\(P_i,P_{i+1},\cdots,P_{j-1},P_j\)组成的多边形的直径的平方,在\(i>j\)时表示\(P_i,P_{i+1},\cdots,P_n,P_1,\cdots,P_{j-1},P_j\)组......
  • 题解 P9697【[GDCPC2023] Canvas】
    好题。后面的操作会覆盖前面的操作,这东西不好处理,我们不妨时光倒流,将问题转化为一个位置一旦被填了数,就再也不会变了。如果解决了这个问题,只需将操作序列倒过来,就得到了原问题的解。显然,所有\(x_i=y_i=2\)的操作会最先被执行,所有\(x_i=y_i=1\)的操作会最后被执行。只需要给......