#line 2 "random_graph/gen.hpp"
#include<array>
#include<cassert>
#include<chrono>
#include<numeric>
#include<set>
#include<vector>#line 2 "random_graph/graph.hpp"
#include<algorithm>
#line 5 "random_graph/graph.hpp"
#include<iostream>
#line 7 "random_graph/graph.hpp"
usingnamespacestd;// 辺の重みはlong long決め打ちusingW=longlong;// 辺の情報を格納する構造体structEdge{intu,v;Ww;intidx;Edge(int_u,int_v,W_w=1,int_idx=-1):u(_u),v(_v),w(_w),idx(_idx){}};// グラフの情報を格納する構造体structGraph{private:intn,m;vector<Edge>es;boolweighted;public:Graph(int_n=0,bool_weighted=false):n(_n),m(0),weighted(_weighted){}intedges_size()const{returnm;}// u -> v, 重み w の辺を追加// 0-indexed で追加する必要ありvoidadd_directed_edge(intu,intv,Ww=1,intidx=-1){es.emplace_back(u,v,w,idx);m++;}// min(u,v) -> max(u,v), 重み w の辺を追加// 0-indexed で追加する必要ありvoidadd_undirected_edge(intu,intv,Ww=1,intidx=-1){intmn=min(u,v),mx=max(u,v);add_directed_edge(mn,mx,w,idx);}// 隣接リストを返すvector<vector<Edge>>adjacent_list(booldirected=false)const{vector<vector<Edge>>g(n);for(auto&[u,v,w,i]:es){g[u].emplace_back(u,v,w,i);if(!directed)g[v].emplace_back(v,u,w,i);}returng;}// 隣接行列を返すvector<vector<W>>adjacent_matrix(booldirected=false)const{vector<vector<W>>g(n,vector<W>(n,0));for(auto&[u,v,w,_]:es){g[u][v]=w;if(!directed)g[v][u]=w;}returng;}// グラフを隣接行列の形式で出力voidprint_matrix(ostream&os,booldirected=false)const{autog=adjacent_matrix(directed);for(inti=0;i<n;i++){for(intj=0;j<n;j++){os<<g[i][j]<<" \n"[j==n-1];}}}// グラフの辺情報を一般的な形式で出力voidprint_edge(ostream&os,boolorigin_0=false)const{for(auto&e:es){os<<e.u+(origin_0?0:1);os<<" "<<e.v+(origin_0?0:1);if(weighted)os<<" "<<e.w;os<<"\n";}}// グラフを一般的な形式で出力voidprint(ostream&os,boolorigin_0=false)const{os<<n<<" "<<m<<"\n";print_edge(os,origin_0);}friendostream&operator<<(ostream&os,constGraph&g){g.print(os);returnos;}};#line 2 "random_graph/random.hpp"
// SPDX-License-Identifier: Apache-2.0// This file includes code derived from Library Checker Problems:// https://github.com/yosupo06/library-checker-problems/blob/1e3da4fd4135f4f3cb3a6d76b51c827f7d987942/common/random.h//// The original work is licensed under the Apache License, Version 2.0.//// Local modifications in this repository:// - Moved #pragma once to the first line for oj-bundle compatibility.// - Made this header self-contained by adding missing standard library// includes and removing an unused include.#line 17 "random_graph/random.hpp"
#include<cstddef>
#include<cstdint>
#line 21 "random_graph/random.hpp"
#include<string>
#include<utility>
#line 24 "random_graph/random.hpp"
structRandom{private:// Use xoshiro256**// References: http://xoshiro.di.unimi.it/xoshiro256starstar.cstaticuint64_trotl(constuint64_tx,intk){return(x<<k)|(x>>(64-k));}std::array<uint64_t,4>s;uint64_tnext(){constuint64_tresult_starstar=rotl(s[1]*5,7)*9;constuint64_tt=s[1]<<17;s[2]^=s[0];s[3]^=s[1];s[1]^=s[2];s[0]^=s[3];s[2]^=t;s[3]=rotl(s[3],45);returnresult_starstar;}// random choice from [0, upper]uint64_tnext(uint64_tupper){if(!(upper&(upper+1))){// b = 00..0011..11returnnext()&upper;}intlg=63-__builtin_clzll(upper);uint64_tmask=(lg==63)?~0ULL:(1ULL<<(lg+1))-1;while(true){uint64_tr=next()&mask;if(r<=upper)returnr;}}public:Random(uint64_tseed=0){// Use splitmix64// Reference: http://xoshiro.di.unimi.it/splitmix64.cfor(inti=0;i<4;i++){uint64_tz=(seed+=0x9e3779b97f4a7c15);z=(z^(z>>30))*0xbf58476d1ce4e5b9;z=(z^(z>>27))*0x94d049bb133111eb;s[i]=z^(z>>31);}}// random choice from [lower, upper]template<classT>Tuniform(Tlower,Tupper){assert(lower<=upper);returnT(lower+next(uint64_t(upper-lower)));}// random choice from false or truebooluniform_bool(){returnuniform(0,1)==1;}// random choice from [0.0, 1.0]doubleuniform01(){uint64_tv=next(1ULL<<63);returndouble(v)/(1ULL<<63);}// random choice non-empty sub-interval from interval [lower, upper)// equal: random choice 2 disjoint elements from [lower, upper]template<classT>std::pair<T,T>uniform_pair(Tlower,Tupper){assert(upper-lower>=1);Ta,b;do{a=uniform(lower,upper);b=uniform(lower,upper);}while(a==b);if(a>b)std::swap(a,b);return{a,b};}// generate random lower string that length = nstd::stringlower_string(std::size_tn){std::stringres="";for(std::size_ti=0;i<n;i++){res+=uniform('a','z');}returnres;}// random shuffletemplate<classIter>voidshuffle(Iterfirst,Iterlast){if(first==last)return;// Reference and edit:// cpprefjp - C++日本語リファレンス// (https://cpprefjp.github.io/reference/algorithm/shuffle.html)intlen=1;for(autoit=first+1;it!=last;it++){len++;intj=uniform(0,len-1);if(j!=len-1)iter_swap(it,first+j);}}// generate random permutation that length = ntemplate<classT>std::vector<T>perm(std::size_tn){std::vector<T>idx(n);std::iota(idx.begin(),idx.end(),T(0));shuffle(idx.begin(),idx.end());returnidx;}// random choice n elements from [lower, upper]template<classT>std::vector<T>choice(std::size_tn,Tlower,Tupper){assert(T(n)<=upper-lower+1);std::set<T>res;while(res.size()<n)res.insert(uniform(lower,upper));return{res.begin(),res.end()};}}global_gen;#line 12 "random_graph/gen.hpp"
// ジェネレータ本体structUndirectedGraphGenerator{private:// 乱数生成器 (staticメンバ変数の代わり)Random&_gen(){staticRandomgen{};returngen;}// [l, r]上の一様乱数を生成longlongrandom(longlongl,longlongr){assert(l<=r&&"UndirectedGraphGenerator::random(l, r)");return_gen().uniform(l,r);}// vをランダムにシャッフルtemplate<typenameU>voidrandom_shuffle(vector<U>&v){_gen().shuffle(begin(v),end(v));}W_w_min,_w_max;// 辺の重みを設定voidset_weight(boolweighted,Ww_min,Ww_max){_w_min=w_min,_w_max=w_max;if(!weighted)_w_min=_w_max=1;}// 辺を追加voidadd_edge(Graph&g,inti,intj){Ww=_w_min==_w_max?_w_min:random(_w_min,_w_max);g.add_undirected_edge(i,j,w);}// 乱数生成sunsignedlonglongrandom_seed()const{unsignedlonglongseed=chrono::duration_cast<chrono::nanoseconds>(chrono::high_resolution_clock::now().time_since_epoch()).count();returnseed;}public:UndirectedGraphGenerator(unsignedlonglongseed=0):_w_min(1),_w_max(1){if(seed==0)seed=random_seed();set_seed(seed);}// シードを設定するvoidset_seed(unsignedlonglongseed){_gen()=Random{seed^1333uLL};}/**
* ランダムケース生成用。
* 条件を満たす全ての関数の中からランダムに1つを選んでグラフを生成。
*/Graphtest(intn,boolis_tree=true,boolweighted=false,Ww_min=1,Ww_max=1){usingF=Graph(UndirectedGraphGenerator::*)(int,bool,W,W);vector<F>f{tree,path,star,perfect,simple,namori,simple_sparse};intmx=is_tree?2:6;return(this->*f[random(0,mx)])(n,weighted,w_min,w_max);}// ランダムな無向の木を出力Graphtree(intn,boolweighted=false,Ww_min=1,Ww_max=1){set_weight(weighted,w_min,w_max);Graphg(n,weighted);if(n==2)add_edge(g,0,1);if(n<=2)returng;vector<int>code(n-2),deg(n,1);for(auto&i:code)i=random(0,n-1),deg[i]++;set<int>js;for(intj=0;j<n;j++){if(deg[j]==1)js.insert(j);}for(auto&i:code){intj=*js.begin();add_edge(g,i,j);js.erase(begin(js));if(--deg[i]==1)js.insert(i);deg[j]--;}intu=*js.begin(),v=*next(js.begin());add_edge(g,u,v);assert(g.edges_size()==n-1);returng;}// ランダムな無向のパスグラフを出力Graphpath(intn,boolweighted=false,Ww_min=1,Ww_max=1){set_weight(weighted,w_min,w_max);vector<int>ord(n);iota(begin(ord),end(ord),0);random_shuffle(ord);Graphg(n,weighted);for(inti=0;i<n-1;i++)add_edge(g,ord[i],ord[i+1]);returng;}// ランダムな無向のスターグラフを出力Graphstar(intn,boolweighted=false,Ww_min=1,Ww_max=1){set_weight(weighted,w_min,w_max);vector<int>ord(n);iota(begin(ord),end(ord),0);random_shuffle(ord);Graphg(n,weighted);for(inti=1;i<n;i++)add_edge(g,ord[0],ord[i]);returng;}// 完全グラフGraphperfect(intn,boolweighted=false,Ww_min=1,Ww_max=1){set_weight(weighted,w_min,w_max);Graphg(n,weighted);for(inti=0;i<n;i++){for(intj=i+1;j<n;j++)add_edge(g,i,j);}returng;}// 単純グラフGraphsimple(intn,boolweighted=false,Ww_min=1,Ww_max=1){set_weight(weighted,w_min,w_max);Graphg(n,weighted);for(inti=0;i<n;i++){for(intj=i+1;j<n;j++){if(random(0,1)==1)add_edge(g,i,j);}}returng;}// なもりグラフGraphnamori(intn,boolweighted=false,Ww_min=1,Ww_max=1){set_weight(weighted,w_min,w_max);Graphg(n,weighted);for(inti=0;i<n;i++){if(i==0){add_edge(g,i,random(1,n-1));}else{add_edge(g,i,random(0,i-1));}}returng;}// 疎な単純グラフGraphsimple_sparse(intn,boolweighted=false,Ww_min=1,Ww_max=1){set_weight(weighted,w_min,w_max);if(n==0)returnGraph{};intm=random(0,n-1);set<pair<int,int>>es;while((int)es.size()<m){inti=random(0,n-1);intj=random(0,n-1);if(i>=j)continue;es.emplace(i,j);}Graphg(n,weighted);for(auto&[i,j]:es)add_edge(g,i,j);returng;}}undirected;