CF1680F Lenient Vertex Cover 题解
CF1680F Lenient Vertex Cover 题解
这道题和「JOISC 2014 Day3」电压非常类似,或者说就是一道题。
题意就是给你一个图,问能否对所有点黑白染色,允许最多一条边的两个顶点都染成黑色。
黑白染色后其实就是一个二分图,那如果有一条边的两个顶点染成黑色,就是说去掉该边后,剩下的图为二分图,注意这里要保证两个顶点的颜色相同,否则无法同时染成黑色。
那么我们考虑线段树分治来做。具体地,对于第
时间复杂度 但是其他方法可以做到线性,我太菜力
代码:
#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; }