Problem:
Score : 700 points

Problem Statement

Snuke's mother gave Snuke an undirected graph consisting of N vertices numbered 0 to N-1 and M edges.
This graph was connected and contained no parallel edges or self-loops.

One day, Snuke broke this graph.
Fortunately, he remembered Q clues about the graph.
The i-th clue (0 \leq i \leq Q-1) is represented as integers A_i,B_i,C_i and means the following:

If C_i=0: there was exactly one simple path (a path that never visits the same vertex twice) from Vertex A_i to B_i.

If C_i=1: there were two or more simple paths from Vertex A_i to B_i.

Snuke is not sure if his memory is correct, and worried whether there is a graph that matches these Q clues.
Determine if there exists a graph that matches Snuke's memory.

Constraints

2 \leq N \leq 10^5

N-1 \leq M \leq N \times (N-1)/2

1 \leq Q \leq 10^5

0 \leq A_i,B_i \leq N-1

A_i \neq B_i

0 \leq C_i \leq 1

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N M Q
A_0 B_0 C_0
A_1 B_1 C_1
\vdots
A_{Q-1} B_{Q-1} C_{Q-1}

Output

If there exists a graph that matches Snuke's memory, print Yes; otherwise, print No.

Sample Input 1

5 5 3
0 1 0
1 2 1
2 3 0

Sample Output 1

Yes

For example, consider a graph with edges (0,1),(1,2),(1,4),(2,3),(2,4). This graph matches the clues.

Sample Input 2

4 4 3
0 1 0
1 2 1
2 3 0

Sample Output 2

No

Sample Input 3

10 9 9
7 6 0
4 5 1
9 7 0
2 9 0
2 3 0
4 1 0
8 0 0
9 1 0
3 0 0

Sample Output 3

No

Solution in C++14 (GCC 5.4.1) (judge verdict: Wrong Answer)

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
#ifdef ENABLE_DEBUG
#define dump(a) cerr<<#a<<"="<<a<<endl
#define dumparr(a,n) cerr<<#a<<"["<<n<<"]="<<a[n]<<endl
#else
#define dump(a) 
#define dumparr(a,n) 
#endif
#define FOR(i, a, b) for(ll i = a;i < b;i++)
#define For(i, a) FOR(i, 0, a)
#define REV(i, a, b) for(ll i = b-1;i >= a;i--)
#define Rev(i, a) REV(i, 0, a)
#define REP(a) For(i, a)

typedef long long int ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef pair<ll, ll> pll;
typedef pair<ll,pll> ppll;
typedef vector<ll> vll;

const ll INF=(1LL<<50);

template<class S,class T>
std::ostream& operator<<(std::ostream& os,pair<S,T> a){
  os << "(" << a.first << "," << a.second << ")";
  return os;
}
template<class T>
std::ostream& operator<<(std::ostream& os,vector<T> a){
  os << "[ ";
  REP(a.size()){
    os<< a[i] << " ";
  }
  os<< " ]";
  return os;
}
class UF{
  vector<int> par,rank,size_uf;
  int chunk_size;
public:
  UF(int size):chunk_size(size){
    for (int i = 0; i < size; i++) {
      par.push_back(i);
      rank.push_back(0);
      size_uf.push_back(1);
    }
  }
  int find(int x){
    if(par[x]==x)return x;
    return par[x]=find(par[x]);
  }
  void unite(int x,int y){
    x=find(x);
    y=find(y);
    if(x==y)return;
    --chunk_size;
    if(rank[x]<rank[y]){
      par[x]=y;
      size_uf[y]+=size_uf[x];
    }
    else{
      par[y]=x;
      size_uf[x]+=size_uf[y];
      if(rank[x]==rank[y])rank[x]++;
    }
  }
  bool same(int x,int y){
    return find(x)==find(y);
  }
  int operator [](int x){
    return this->find(x);
  }
  int size(int x){
    x=find(x);
    return size_uf[x];
  }
  int uf_size(){
    return this->chunk_size;
  }
};

const string YES = "Yes";
const string NO = "No";

void solve(long long N, long long M, long long Q, std::vector<long long> A, std::vector<long long> B, std::vector<long long> C){
  UF uf(N);
  tree<ll, null_type, less<ll>, rb_tree_tag, tree_order_statistics_node_update>  s;
  REP(Q){
    if(C[i]==0){
      uf.unite(A[i],B[i]);
    }
  }
  REP(N){
    s.insert(uf[i]);
  }
  UF ufuf(s.size());
  REP(Q){
    if(C[i]){
      if(uf.same(A[i],B[i])){
        cout<<NO<<endl;
        return;
      }
      ll tmpa=s.order_of_key(uf[A[i]]),tmpb=s.order_of_key(uf[B[i]]);
      ufuf.unite(s.order_of_key(uf[A[i]]),s.order_of_key(uf[B[i]]));
    }
  }
  if(uf.uf_size()==2&&ufuf.uf_size()==1){
    cout<<NO<<endl;
    return ;
  }
  ll tmp=uf.uf_size()-ufuf.uf_size();
  ll tmp2=(tmp==0?0:(tmp==1?3:tmp+1));
  ll min_edge=N-uf.uf_size()+tmp2;
  ll max_edge=N-uf.uf_size()+(uf.uf_size()*(uf.uf_size()-1))/2;
  if(min_edge<=M&&M<=max_edge){
    cout<<YES<<endl;
  }else{
    cout<<NO<<endl;
  }
}

int main(){
    long long N;
    scanf("%lld",&N);
    long long M;
    scanf("%lld",&M);
    long long Q;
    scanf("%lld",&Q);
    std::vector<long long> A(Q-1-0+1);
    std::vector<long long> B(Q-1-0+1);
    std::vector<long long> C(Q-1-0+1);
    for(int i = 0 ; i < Q-1-0+1 ; i++){
        scanf("%lld",&A[i]);
        scanf("%lld",&B[i]);
        scanf("%lld",&C[i]);
    }
    solve(N, M, Q, std::move(A), std::move(B), std::move(C));
    return 0;
}