CF603E Pastoral Oddities
CF603E Pastoral Oddities
存在这样满足每个点的度数均为奇数的边集,充分条件是连通块的点数为偶数。
先考虑必要性,加入一边度数和增加 故度数和为偶数,而当满足条件的连通块点数为奇时,度数和必为奇数,矛盾。
证明充分性:对于一个偶数大小的连通块,找出其一棵生成树,从叶子开始根据连向儿子的度数考虑是否添加其到父亲的边,逐步满足,最后除了根之外都满足条件,显然根据奇偶性根也满足条件,故充分性保证。
故用一个按秩合并并查集即可维护连通块是否满足条件。
再考虑边集中的最大边权最小的限制,一棵最小生成树足矣。
在线 LCT
维护最小生成树森林,时间复杂度 。
但非常难写且常数巨大,考虑离线做法。
观察样例得知,时间升序,答案单调递减;还有“最大值最小”一类的词,考虑二分。
多次询问,考虑整体二分。
具体地,离散化权值,再对权值分治,令其为 。
添加权值 的边直到合法,根据第一个合法的位置分治。
注意细节,整体二分后面的状态 需要并查集中含有所有编号 且权值 的边,考虑维护一个可撤销并查集即可。
时间复杂度 。
#include<cstdio>
#include<algorithm>
typedef long long ll;
#define ha putchar(' ')
#define he putchar('\n')
inline int read() {
int x = 0;
char c = getchar();
while (c < '0' || c > '9')
c = getchar();
while (c >= '0' && c <= '9')
x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
return x;
}
inline void write(int x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9)
write(x / 10);
putchar(x % 10 + 48);
}
const int _ = 3e5 + 5;
int n, m, cnt, fa[_], sz[_], t, s[_], ans[_];
struct abc {
int u, v, w, id;
bool operator < (const abc &t) {
return w < t.w;
}
} e[_], b[_];
int find(int x) {
return fa[x] == x ? x : find(fa[x]);
}
void merge(int u, int v) {
u = find(u), v = find(v);
if (u == v) return;
if (sz[u] < sz[v]) std::swap(u, v);
if ((sz[u] & 1) && (sz[v] & 1)) cnt -= 2;
sz[u] += sz[v], fa[v] = u, s[++t] = v;
}
void ers(int lim) {
while (t > lim) {
int v = s[t--], u = fa[v];
fa[v] = v, sz[u] -= sz[v];
if ((sz[u] & 1) && (sz[v] & 1)) cnt += 2;
}
}
void solve(int l, int r, int vl, int vr) {
if (l > r || vl > vr) return;
if (vl == vr) {
for (int i = l; i <= r; ++i) ans[i] = b[vl].w;
return;
}
int mid = (vl + vr) >> 1, nw = t;
for (int i = vl; i <= mid; ++i)
if (b[i].id < l) merge(b[i].u, b[i].v);
int Id = r + 1, nw2 = t;
for (int i = l; i <= r; ++i) {
if (e[i].w <= b[mid].w) merge(e[i].u, e[i].v);
if (!cnt) {
Id = i;
break;
}
}
ers(nw2);
solve(l, Id - 1, mid + 1, vr);
ers(nw);
for (int i = l; i < Id; ++i)
if (e[i].w <= b[vl].w) merge(e[i].u, e[i].v);
solve(Id, r, vl, mid);
ers(nw);
}
signed main() {
n = cnt = read(), m = read();
for (int i = 1; i <= n; ++i) fa[i] = i, sz[i] = 1;
for (int i = 1; i <= m; ++i) {
e[i].u = read(), e[i].v = read(), e[i].w = read();
e[i].id = i, b[i] = e[i];
}
std::sort(b + 1, b + m + 1);
b[m + 1].w = -1;
solve(1, m, 1, m + 1);
for (int i = 1; i <= m; ++i) write(ans[i]), he;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18121988