CF603E Pastoral Oddities 题解
首先“每个点度数均为奇数”这个限制显然无法直接处理。手玩一些样例后容易发现这个限制等价于原图中只存在大小为偶数的连通块。这个限制我们是好规约的,在无向图上并查集维护连通性可以处理。
动态插入边的操作是困难的,不妨先考虑静态的情形如何解决。首先需要明确的是连尽量多的边一定不劣,原因是并不会有任意一条边使得大小为奇数的连通块数量增加。那么要使得最大边权最小,不妨将边按边权从小到大来排序,不断加入新的边直到不存在大小为奇数的连通块为止。
现在考虑动态加边的情形。容易发现答案是单调不增的,那么不妨从后向前来考虑每一次询问的答案,这样一来答案应当是递增的。将边按边权从小向大排序后我们同时动态维护一个指针,每次动态加边直到满足条件为止。然而注意到每条边在时间轴上有一个影响范围,于是使用线段树分治来维护即可。
代码:
#include <bits/stdc++.h>
#define N 300005
using namespace std;
int n, m;
struct node {
int x, y, z, id;
bool operator < (const node &a) const {
return z < a.z;
}
} t[N];
int fa[N], siz[N];
int fnd(int x) {
return x == fa[x] ? x : fnd(fa[x]);
}
#define pii pair<int, int>
#define mk make_pair
pii stk[N];
int top, cnt;
void mge(int x, int y) {
x = fnd(x), y = fnd(y);
if (x == y) return;
if (siz[x] > siz[y]) swap(x, y);
fa[x] = y;
cnt -= siz[x] & 1;
cnt -= siz[y] & 1;
siz[y] += siz[x];
cnt += siz[y] & 1;
stk[++top] = mk(x, y);
}
void del(int t) {
while (top > t) {
pii p = stk[top--];
int x = p.first, y = p.second;
cnt -= siz[y] & 1;
fa[x] = x;
siz[y] -= siz[x];
cnt += siz[x] & 1;
cnt += siz[y] & 1;
}
}
struct Node {
int l, r;
vector<pii>v;
} e[N << 2];
#define l(i) e[i].l
#define r(i) e[i].r
#define v(i) e[i].v
#define lc (p << 1)
#define rc (lc | 1)
void build(int p, int l, int r) {
l(p) = l, r(p) = r;
if (l == r) return;
int mid = (l + r) >> 1;
build(lc, l, mid);
build(rc, mid + 1, r);
}
void update(int p, int l, int r, pii x) {
if (l > r || l > r(p) || l(p) > r) return;
if (l <= l(p) && r(p) <= r) return v(p).push_back(x);
update(lc, l, r, x);
update(rc, l, r, x);
}
int nw, ans[N];
void dfs(int p) {
int tp = top;
for (auto i : v(p)) mge(i.first, i.second);
if (l(p) == r(p)) {
while (1) {
if (cnt == 0 || nw == m) break;
++nw;
if (t[nw].id <= l(p)) {
mge(t[nw].x, t[nw].y);
update(1, t[nw].id, l(p) - 1, mk(t[nw].x, t[nw].y));
}
}
if (cnt) ans[l(p)] = -1;
else ans[l(p)] = t[nw].z;
}
else dfs(rc), dfs(lc);
del(tp);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
build(1, 1, m);
for (int i = 1; i <= m; i++) cin >> t[i].x >> t[i].y >> t[i].z, t[i].id = i;
sort(t + 1, t + m + 1);
iota(fa + 1, fa + n + 1, 1);
fill(siz + 1, siz + n + 1, 1);
cnt = n;
dfs(1);
for (int i = 1; i <= m; i++) cout << ans[i] << '\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律