BC的官方题解已经讲的不能再清楚了。。。
对于问题1,我们只需要进行二分图染色判定这个图是否是二分图即可
二分图中必定不存在奇环,而非二分图中必定存在奇环
对于问题2,首先我们注意到一个环一定存在于双联通分量(既去掉任何一条边后仍然联通的点集)内
通过tarjan算法,可以分离出所有的双联通分量,然后分别检查其中是否存在偶环
对于一个双联通分量,如果它仅仅是一个环,那么只需判断它是否是偶环即可
否则其中必定存在两个缠绕(共享至少一条边)的环,若这两个环的都是奇环,那么去掉共享的边之后可以组成一个大偶环
因此,除非一个双联通分量仅仅是一个奇环,那么其中必定存在偶环
而我们可以发现,若一个非单点的双联通分量仅仅由一个环构成,那么它的点数必定等于边数,据此判断即可
时间复杂度O(N + M)
#include <iostream> #include <queue> #include <stack> #include <map> #include <set> #include <bitset> #include <cstdio> #include <algorithm> #include <cstring> #include <climits> #include <cstdlib> #include <cmath> #include <time.h> #define maxn 100005 #define maxm 600005 #define eps 1e-12 #define mod 998244353 #define INF 0x3f3f3f3f #define PI (acos(-1.0)) #define lowbit(x) (x&(-x)) #define mp make_pair #define ls o<<1 #define rs o<<1 | 1 #define lson o<<1, L, mid #define rson o<<1 | 1, mid+1, R #pragma comment(linker, "/STACK:102400000,102400000") #define pii pair<int, int> typedef long long LL; typedef unsigned long long ULL; //typedef int LL; using namespace std; LL qpow(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base;base=base*base;b/=2;}return res;} LL powmod(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base%mod;base=base*base%mod;b/=2;}return res;} // head struct Edge { int u, v; Edge *next; }*H[maxn], E[maxm], *edges; int dfn[maxn]; int low[maxn]; int cnt[maxn]; int vis[maxn]; int tcnt[maxn]; int belong[maxn]; stack<int> s; int n, m, dfs_clock, scnt, ok; void addedges(int u, int v) { edges->u = u; edges->v = v; edges->next = H[u]; H[u] = edges++; } void init() { scnt = dfs_clock = 0; edges = E; memset(H, 0, sizeof H); memset(dfn, 0, sizeof dfn); memset(cnt, 0, sizeof cnt); memset(vis, -1, sizeof vis); memset(tcnt, 0, sizeof tcnt); } void tarjan(int u, int fa) { dfn[u] = low[u] = ++dfs_clock; s.push(u); bool flag = 1; for(Edge *e = H[u]; e; e = e->next) { int v = e->v; if(v == fa && flag) { flag = 0; continue; } if(!dfn[v]) { tarjan(v, u); low[u] = min(low[u], low[v]); } else low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]) { ++scnt; int t; do{ t = s.top(); s.pop(); belong[t] = scnt; cnt[scnt]++; }while(t != u); } } void dfs(int u, int fa) { for(Edge *e = H[u]; e; e = e->next) if(e->v != fa) { if(vis[e->v] == -1) vis[e->v] = vis[u] ^ 1, dfs(e->v, u); else if(vis[e->v] == vis[u]) ok = 1; } } void work() { int u, v; scanf("%d%d", &n, &m); for(int i = 1; i <= m; i++) { scanf("%d%d", &u, &v); addedges(u, v); addedges(v, u); } ok = 0; for(int i = 1; i <= n; i++) if(vis[i] == -1) vis[i] = 0, dfs(i, 0); if(ok) printf("YES\n"); else printf("NO\n"); for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i, 0); for(Edge *e = E; e != edges; e += 2) if(belong[e->v] == belong[e->u]) tcnt[belong[e->u]]++; ok = 0; for(int i = 1; i <= scnt; i++) { if(cnt[i] == tcnt[i] && cnt[i] % 2 == 0) ok = 1; else if(cnt[i] != tcnt[i] && cnt[i] != 1) ok = 1; } if(ok) printf("YES\n"); else printf("NO\n"); } int main() { int _; scanf("%d", &_); while(_--) { init(); work(); } return 0; }