Official

D - 採点 / Marking Editorial by leaf1415


本問題を解くには、問題文の指示にある通り、入力が下記の条件を全て満たすかどうかを判定すれば良いです。

  1. すべての \(i = 1, 2, \ldots, M\) について、\(1 \leq u_i, v_i \leq N\)
  2. 与えられたグラフは単純。すなわち、
    • 任意の頂点 \(v\) について、\(v\)\(v\) を結ぶ辺は存在しない。
    • 任意の \(2\) つの頂点 \(u, v\) について、\(u\)\(v\) を結ぶ辺は高々 \(1\) 本である。

上記 2. の \(1\) つ目の条件の判定では、すべての \(i\)\(u_i \neq v_i\) かを判定すれば良いです。

上記 2. の \(2\) つ目の条件の判定では、\(1 \leq i \lt j \leq M\) を満たすすべての整数組 \((i, j)\) について、\(i\) 番目の辺と \(j\) 番目の辺が異なるかを判定すれば良いですが、そのような整数組は \(\mathrm{\Theta}(N^2)\) 個あるため、それらすべてを実際に調べる方法では実行制限時間に間に合わせることは絶望的です。 より高速な判定方法として、

\(M\) 本の辺を \(1\) つずつ順に平衡二分木に追加していく。 各辺を追加する前に、これから追加する辺と同一の辺がすでに平衡二分木に追加されているかを判定する。

という、\(\mathrm{O}(N \log N)\) 時間の方法を用いることで、実行制限時間に間に合わせることができます。

\((u_i, v_i) \neq (u_j, v_j)\) であっても、\((u_i, v_i) = (v_j, u_j)\) であれば、\(i\) 番目の辺と \(j\) 番目の辺は同一の辺であることに注意してください。

以下に C++ 言語による正解例を記載します。

#include <iostream>
#include <utility>
#include <set>
using namespace std;

int n, m;
int u[200005], v[200005];

int main(void)
{
  cin >> n >> m;
  for(int i = 1; i <= m; i++) cin >> u[i] >> v[i];
  
  for(int i = 1; i <= m; i++){
    if(!(1 <= u[i] && u[i] <= n && 1 <= v[i] && v[i] <= n)){
      cout << "No" << endl;
      return 0;
    }
  }
  
  for(int i = 1; i <= m; i++){
    if(u[i] == v[i]){
      cout << "No" << endl;
      return 0;
    }
  }
  
  set<pair<int, int>> S;
  for(int i = 1; i <= m; i++){
    if(u[i] > v[i]) swap(u[i], v[i]);
    if(S.count({u[i], v[i]})){
      cout << "No" << endl;
      return 0;
    }
    S.insert({u[i], v[i]});
  }
  
  cout << "Yes" << endl;

  return 0;
}

posted:
last update: