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 <iostream>
#include <complex>
#include <vector>
#include <string>
#include <algorithm>
#include <cstdio>
#include <numeric>
#include <cstring>
#include <ctime>
#include <cstdlib>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <list>
#include <cmath>
#include <bitset>
#include <cassert>
#include <queue>
#include <stack>
#include <deque>
#include <random>


using namespace std;
template<typename T1, typename T2> inline void chkmin(T1 &a, T2 b) {if (a > b) a = b;}
template<typename T1, typename T2> inline void chkmax(T1 &a, T2 b) {if (a < b) a = b;}
#define files(FILENAME) read(FILENAME); write(FILENAME)
#define read(FILENAME) freopen((FILENAME + ".in").c_str(), "r", stdin)
#define write(FILENAME) freopen((FILENAME + ".out").c_str(), "w", stdout)
#define all(c) (c).begin(), (c).end()
#define sz(c) (int)(c).size()
#define left left228
#define right right228
#define y1 y1228
#define mp make_pair
#define pb push_back
#define y2 y2228
#define rank rank228
using ll = long long;
const string FILENAME = "input";
const int MAXN = 200228;


int n;
long long m;
int q;
int parent[MAXN];
int sz[MAXN];


int findset(int v) {
	if (v == parent[v]) {
		return v;
	}
	return parent[v] = findset(parent[v]);
}


void merge(int a, int b) {
	a = findset(a);
	b = findset(b);
	if (a == b) {
		return;
	}
	parent[a] = b;
	sz[b] += sz[a]; 
}


vector<int> g[MAXN];
bool used[MAXN];
vector<int> st;


void dfs(int u) {
	st.pb(sz[u]);
	used[u] = true;
	for (auto h: g[u]) {
		if (!used[h]) {
			dfs(h);
		}
	}
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
 	//read(FILENAME);
 	cin >> n >> m >> q;
 	for (int i = 0; i < n; i++) {
 		parent[i] = i;
 		sz[i] = 1;
 	}
 	vector<pair<int, int> > gt;
 	for (int i = 0; i < q; i++) {
 		int a, b, c;
 		cin >> a >> b >> c;
 		if (c == 1) {
 			merge(a, b);
 		} else {
 			gt.pb({a, b});
 		}
 	}
 	long long total = 1LL * n * (n - 1) / 2;
 	set<pair<int, int> > s;
 	for (auto x: gt) {
 		int t = findset(x.first);
 		int t1 = findset(x.second);
 		if (t == t1) {
 			cout << "No\n";
 			exit(0);
 		}
 		if (t > t1) {
 			swap(t, t1);
 		}
 		if (s.find({t, t1}) == s.end()) {
 			s.insert({t, t1});
 			g[t].pb(t1);
 			g[t1].pb(t);
 		}
 	}
 	int k = n - 1;
 	int cnt = 0;
 	vector<pair<int, int> > gays;
 	for (int i = 0; i < n; i++) {
 		if (findset(i) == i) {
 			if (!used[i]) {
 				st.clear();
 				dfs(i);
 				ll sum = 0;
 				bool was = false;
 				bool was1 = false;
 				int cntp = 0;
 				int cntp1 = 0;
 				for (auto x: st) {
 					total -= sum * x;
 					if (x == 2) {
 						was = true;
 					}
 					if (x >= 2) {
 						was1 = true; 
 					}
 					sum += x;
 					if (x == 2) {
 						cntp++;
 					}
 					if (x > 2) {
 						cntp1++;
 					}
 				}
 				gays.push_back({cntp, cntp1});
 				cnt += was1;
 				if (was && sum == total) {
 					cout << "No\n";
 					exit(0);
 				}
 			}
 		}
 	}
 	set<pair<int, int> > st;
 	int fk = 0;
 	for (int i = 0; i < sz(gays); i++) {
 		if (gays[i].first) {
 			gays[i].first--;
 			fk = true;
 		} else if (gays[i].second) {
 			gays[i].second--;
 			fk = true;
 		}
 	}
 	if (fk) {
 		k++;
 	}
 	 for (int i = 0; i < sz(gays); i++) {
 	 	k += gays[i].first + gays[i].second;
 		st.insert({gays[i].first, i});
 	}
 	while (sz(st) >= 2) {
 		auto a = *st.rbegin();
 		auto b = *st.begin();
 		st.erase(a);
 		st.erase(b);
 		a.first--;
 		b.first--;
 		gays[a.second].first--;
 		gays[b.second].first--;
 		if (a.first > 0) {
 			s.insert(a);
 		}
 		if (b.first > 0) {
 			s.insert(b);
 		}
 	}
 	int sum = 0;
 	for (int i = 0; i < sz(gays); i++) {
 		sum += gays[i].second;
 	}
 	for (int i = 0; i < sz(gays); i++) {
 		if (gays[i].first) {
 			k += gays[i].first - min(gays[i].first, sum - gays[i].second);
 		}
  	}
 	if (k > m) {
 		cout << "No\n";
 		exit(0);
 	}
 	if (total < m) {
 		cout << "No\n";
 		exit(0);
 	}
 	cout << "Yes\n";
	return 0; 	
}