Problem - 557D - Codeforces
- 他の人のコードを見て union find を使う方法を知った。グラフの二色塗り分けを union find でやるなんて発想に目から鱗が落ちた。
- 以下は dfs と union find を使う2つの実装。
class Div2D {
public:
void solve_dfs(void)
{
int N, M;
cin>>N>>M;
if ( M == 0 )
{
cout<<"3 "<<(ll)N*(N-1)*(N-2)/6<<endl;
return;
}
vector<vector<int>> tree(N);
UFTree uft(N);
REP(i, M)
{
int a, b;
cin>>a>>b;
--a;
--b;
tree[a].push_back(b);
tree[b].push_back(a);
}
ll way = 0;
ll maxCnt = 0;
vector<int> color(N, 0);
REP(i, N)
{
if ( color[i] != 0 )
continue;
ll nB = 0;
ll nW = 0;
bool found = false;
stack<pair<int,int>> stack;
color[i] = 1;
stack.emplace(i, 1);
while ( !stack.empty() )
{
int x, c, nc;
tie(x, c) = stack.top();
if (c == 1)
{
nc = -1;
++nW;
}
else
{
nc = 1;
++nB;
}
stack.pop();
for (auto y : tree[x])
{
if (color[y] == c)
{
found = true;
break;
}
if (color[y] == nc)
continue;
color[y] = nc;
stack.emplace(y, nc);
}
}
if ( found )
{
cout<<"0 1"<<endl;
return;
}
way += (nB*(nB-1)/2 + nW*(nW-1)/2);
maxCnt = max(maxCnt, nW+nB);
}
if ( maxCnt <= 2 )
{
cout<<"2 "<<(ll)M*(N-2)<<endl;
return;
}
cout<<"1 "<<way<<endl;
}
void solve_uf(void)
{
int N, M;
cin>>N>>M;
if ( M == 0 )
{
cout<<"3 "<<(ll)N*(N-1)*(N-2)/6<<endl;
return;
}
vector<vector<int>> tree(N);
UFTree uft(2*N);
REP(i, M)
{
int a, b;
cin>>a>>b;
--a;
--b;
tree[a].push_back(b);
tree[b].push_back(a);
uft.unite(a,b+N);
uft.unite(a+N,b);
}
REP(i, N) if (uft[i] == uft[i+N])
{
cout<<"0 1"<<endl;
return;
}
vector<ll> cnt(2*N, 0);
REP(i, N)
++cnt[uft[i]];
ll way = 0;
REP(i, 2*N)
way += cnt[i]*(cnt[i]-1)/2;
if (way > 0)
{
cout<<"1 "<<way<<endl;
return;
}
cout<<"2 "<<(ll)(N-2)*M<<endl;
}
void solve() {
solve_uf();
}
};