#include "testlib.h" #include #include #include #include #include using namespace std; using ll = unsigned long long; using pll = pair; const double eps = 1e-3; void generate_edges_parallel(ll s_start, ll s_end, ll n, const vector &cnt, unsigned int thread_seed, vector> &buffer) { random_t thread_rnd; thread_rnd.setSeed(thread_seed); unordered_map selected; for (ll s = s_start; s < s_end; ++s) { ll k = cnt[s]; if (k == 0) continue; selected.clear(); for (ll i = 0; i < k; ++i) { ll range_size = (n - 1) - i; ll j = thread_rnd.next(1uLL, range_size); ll val_j = selected.count(j) ? selected[j] : j; ll val_last = selected.count(range_size) ? selected[range_size] : range_size; ll e = (val_j < s) ? val_j : val_j + 1; double len = thread_rnd.next(eps, 1.0 / eps); buffer.emplace_back(s, e, len); selected[j] = val_last; } } } int main(int argc, char *argv[]) { // 메인 RNG 초기화 registerGen(argc, argv, 1); ll n = opt("N"); ll m = opt("M"); println(n, m); vector cnt(n + 1, 0); for (ll i = 0; i < m; ++i) { ll s = rnd.next(1uLL, n); cnt[s]++; } const int num_threads = thread::hardware_concurrency(); vector threads; vector thread_seeds; vector>> thread_buffers(num_threads); for (int i = 0; i < num_threads; ++i) { thread_seeds.push_back(rnd.next(1u, 1000000u)); } ll s_batch_size = (n + num_threads) / num_threads; ll s_current = 1; for (int i = 0; i < num_threads; ++i) { ll s_start = s_current; ll s_end = min(s_start + s_batch_size, n + 1); if (s_start >= s_end) break; threads.emplace_back(generate_edges_parallel, s_start, s_end, n, ref(cnt), thread_seeds[i], ref(thread_buffers[i])); s_current = s_end; } for (auto &t : threads) { t.join(); } cout << fixed << setprecision(15); for (int i = 0; i < num_threads; ++i) { for (const auto &edge : thread_buffers[i]) { println(get<0>(edge), get<1>(edge), get<2>(edge)); } } }