CF1680F Lenient Vertex Cover 题解

CF1680F Lenient Vertex Cover 题解

这道题和「JOISC 2014 Day3」电压非常类似,或者说就是一道题。

题意就是给你一个图,问能否对所有点黑白染色,允许最多一条边的两个顶点都染成黑色。

黑白染色后其实就是一个二分图,那如果有一条边的两个顶点染成黑色,就是说去掉该边后,剩下的图为二分图,注意这里要保证两个顶点的颜色相同,否则无法同时染成黑色。

那么我们考虑线段树分治来做。具体地,对于第 i 条边,我们让它的存在时间为 [0,i1][i+1,m+1],表示在第 i 个时刻,只有第 i 条边没有加上,利用可撤销并查集即可维护是否为二分图。而在 m+1 时刻,所有边都被加上,用来判断原图是否为二分图。

时间复杂度 O(nlog2n),时限开得很大,可以过。但是其他方法可以做到线性,我太菜力

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
int read() {
int x = 0; char ch = getchar();
while(ch<'0' || ch>'9') ch = getchar();
while(ch>='0'&&ch<='9') x = x*10+(ch-48), ch = getchar();
return x;
}
struct Edge {
int u, v;
} e[N];
int T;
int n, m;
int fa[N<<1], siz[N<<1], top;
struct xwx {
int x, y, del;
}stk[N<<1];
int find(int x) {
if(x == fa[x]) return x;
return find(fa[x]);
}
bool found;
bool vis[N<<1];
struct SegmentTree {
vector<int> tree[N<<2];
#define ls tr<<1
#define rs tr<<1 | 1
void insert(int tr, int L, int R, int lq, int rq, int id) {
if(lq == L && R == rq) {
tree[tr].push_back(id);
return;
}
int mid = (L+R)>>1;
if(lq<=mid) insert(ls, L, mid, lq, min(mid, rq), id);
if(mid < rq) insert(rs, mid+1, R, max(mid+1, lq), rq, id);
}
void init(int tr, int L, int R) {
tree[tr].clear();
if(L == R) {
return;
}
int mid = (L+R)>>1;
init(ls, L, mid);
init(rs, mid+1, R);
}
void solve(int tr, int L, int R, bool flag) {
int now = top;
for(int i:tree[tr]) {
int fx = find(e[i].u), fy = find(e[i].v);
if(fx == fy) {
flag = 0;
} else {
int f2x = find(e[i].u+n), f2y = find(e[i].v+n);
if(fx != f2y) {
if(siz[fx] > siz[f2y]) swap(fx, f2y);
fa[fx] = f2y;
siz[f2y]+=siz[fx];
stk[++top] = (xwx) {fx, f2y, siz[fx]};
}
if(fy != f2x) {
if(siz[fy] > siz[f2x]) swap(fy, f2x);
fa[fy] = f2x;
siz[f2x]+=siz[fy];
stk[++top] = (xwx) {fy, f2x, siz[fy]};
}
}
}
if(L == R) {
if(flag) {
if(L <= m) {
int tx = find(e[L].u), ty = find(e[L].v);
if(tx!=ty) return;//如果去掉一条边,必须保证两个顶点同色。
vis[tx] = 1;//都染成黑色。
vis[ty] = 1;
}
found = 1;
puts("YES");
for(int i = 1; i<=n; ++i) {
int fi = find(i), f2i = find(i+n);
if(!vis[fi] && !vis[f2i]) {
vis[fi] = 1;//如果这个连通块还没有染色,则让初始节点为黑色。
putchar('1');
} else {
putchar('0'+vis[fi]);
}
}
putchar('\n');
return;
}
return;
}
int mid = (L+R)>>1;
solve(ls, L, mid, flag);
if(found) return;
solve(rs, mid+1, R, flag);
if(found) return;
while(top > now) {
xwx tmp = stk[top--];
fa[tmp.x] = tmp.x;
siz[tmp.y]-=tmp.del;
}
}
}seg;
void init() {
for(int i = 1; i<=n*2; ++i) {
fa[i] = i;
siz[i] = 1;
vis[i] = 0;
}
top = 0;
found = 0;
seg.init(1, 1, m+1);
}
int main() {
T = read();
while(T--) {
n = read(), m = read();
init();
for(int i = 1;i<=m; ++i) {
e[i] = (Edge) {read(), read()};
if(i > 1) seg.insert(1, 1, m+1, 1, i-1, i);
if(i <=m) seg.insert(1, 1, m+1, i+1 ,m+1, i);
}
seg.solve(1, 1, m+1, 1);
if(!found) {
puts("NO");
}
}
return 0;
}
posted @   霜木_Atomic  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示