[AGC071C] Orientable as Desired
Genius_Star · · 题解
或许更好的阅读体验。
思路:
第一眼看上去完全不可做的样子。
那么考虑给
而显然,任意点都满足只有出度或者只有入度,于是一定可以分成两个部分,左边是只有出度的,右边是只有入度的,然后在两个部分之间有左到右的边,一个部分内部没有边,这显然是一个二分图。
所以,当原图不是二分图的时候,选 Yes 即可;否则原图是二分图,此时全
一样的,如果全
但是加上
于是假设有
而
继续考虑,如果只有一项有值的时候都无解,那么更多项有值会不会有解呢?假设
之前一项有值时,断一个点都可以凑出
三项或者更多项有值的时候是类似的,设有值的是
考虑如何判定,对于一个
因为
因为是删点,所以考虑 tarjan 求点双的时候在割点那算一下就行了,需要快速判一个边是否存在,用 set 存一下。
时间复杂度为
完整代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define lowbit(x) (x) & (-(x))
#define popcnt(x) __builtin_popcount(x)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int N = 2e5 + 10;
inline ll read(){
ll x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-')
f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return x * f;
}
inline void write(ll x){
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
bool flag;
int T, n, m, cnt, top;
int dfn[N], low[N], du[N], stk[N];
bool col[N];
set<int> S[N];
vector<int> E[N], V[N];
inline void add(int u, int v){
++du[u], ++du[v];
E[u].push_back(v);
E[v].push_back(u);
S[u].insert(v);
S[v].insert(u);
}
inline void tarjan(int u){
dfn[u] = low[u] = ++cnt;
stk[++top] = u;
for(auto v : E[u]){
if(!dfn[v]){
col[v] = col[u] ^ 1;
tarjan(v);
low[u] = min(low[u], low[v]);
if(low[v] == dfn[u]){
int sum = 0;
while(1){
int x = stk[top--];
sum += S[u].count(x);
if(x == v)
break;
}
V[u].push_back(sum);
du[u] -= sum;
}
}
else{
low[u] = min(low[u], dfn[v]);
if(col[u] ^ col[v] ^ 1)
flag = 1;
}
}
}
inline bool check(vector<int> V){
sort(V.begin(), V.end());
int sum = 0;
for(auto v : V){
if(sum >= v - 1)
sum += v;
else
return 1;
}
return 0;
}
inline void solve(){
cnt = top = flag = 0;
n = read(), m = read();
for(int i = 1; i <= n; ++i){
dfn[i] = low[i] = du[i] = col[i] = 0;
S[i].clear(), E[i].clear(), V[i].clear();
}
while(m--){
int u = read(), v = read();
add(u, v);
}
tarjan(1);
if(flag){
puts("Yes");
return ;
}
for(int u = 1; u <= n; ++u){
if(du[u])
V[u].push_back(du[u]);
if(check(V[u])){
puts("Yes");
return ;
}
// cerr << "now: " << u << '\n';
// for(auto v : V[u])
// cerr << v << ' ';
// cerr << '\n';
}
puts("No");
}
int main(){
T = read();
while(T--)
solve();
return 0;
}