#ifndef MYLOCAL //# pragma GCC target("avx2")//yukiではNG # pragma GCC optimize("O3") # pragma GCC optimize("unroll-loops") #endif #if defined(NDEBUG) #undef NDEBUG #endif #include "bits/stdc++.h" using namespace std; using ll=long long; using dd=long double; using pll=pair; using tll=tuple; using qll=tuple; using namespace chrono; constexpr ll INF = 1201001001001001001; struct Fast{ Fast(){ cin.tie(0); ios::sync_with_stdio(false); cout<::max_digits10); } } fast; #define EXPAND( x ) x//VS用おまじない #define overload3(_1,_2,_3,name,...) name #define overload4(_1,_2,_3,_4,name,...) name #define overload5(_1,_2,_3,_4,_5,name,...) name #define rep1(N) for (ll dmyi = 0; dmyi < (N); dmyi++) #define rep2(i, N) for (ll i = 0; i < (N); i++) #define rep3(i, S, E) for (ll i = (S); i <= (E); i++) #define rep4(i, S, E, t) for (ll i = (S); i <= (E); i+=(t)) #define rep(...) EXPAND(overload4(__VA_ARGS__,rep4,rep3,rep2,rep1)(__VA_ARGS__)) #define dep3(i, E, S) for (ll i = (E); i >= (S); i--) #define dep4(i, E, S, t) for (ll i = (E); i >= (S); i-=(t)) #define dep(...) EXPAND(overload4(__VA_ARGS__, dep4, dep3,_,_)(__VA_ARGS__)) #define ALL1(v) (v).begin(), (v).end() #define ALL2(v,E) (v).begin(), (v).begin()+((E)+1) #define ALL3(v,S,E) (v).begin()+(S), (v).begin()+((E)+1) #define all(...) EXPAND(overload3(__VA_ARGS__, ALL3, ALL2, ALL1)(__VA_ARGS__)) template inline bool chmax(T &a, T b) { if (a < b) { a = b; return true; }return false; } template inline bool chmin(T &a, T b) { if (a > b) { a = b; return true; }return false; } template [[nodiscard]] inline T limithi(T a,T b){ return min(a,b); } template [[nodiscard]] inline T limitlo(T a,T b){ return max(a,b); } template inline bool chlimithi(T &a,T b){ return chmin(a,b); } template inline bool chlimitlo(T &a,T b){ return chmax(a,b); } template inline auto maxe(T &&v,ll S,ll E){ return *max_element(all(v,S,E)); } template inline auto maxe(T &&v){ return *max_element(all(v)); } template inline auto mine(T &&v,ll S,ll E){ return *min_element(all(v,S,E)); } template inline auto mine(T &&v){ return *min_element(all(v)); } template::type::value_type> inline U sum(T &&v,ll S,ll E) {return accumulate(all(v,S,E),U());} template inline auto sum(T &&v) {return sum(v,0,v.end()-v.begin()-1);} template inline ll sz(T &&v){ return (ll)v.size(); } //cin struct cinutil{ template static void cin1core(T &a){ cin>>a; } template static void cin1core(pair &a){ cin1core(a.first),cin1core(a.second); } template static void cin1core(tuple &a){ cinTplRec,sizeof...(Args)-1>()(a); } template static void cin1core(array &a){ for (int i=0; i<(int)N; ++i) cin>>a[i]; } private: template struct cinTplRec{ void operator()(Tpl &a){ cinTplRec()(a); cin1core(get(a)); } }; template struct cinTplRec{ void operator()(Tpl &a){ cin1core(get<0>(a)); } }; }; template T cin1(){ T a; cinutil::cin1core(a); return a; } template tuple cins(){ return cin1>(); } //cout template inline ostream &operator<<(ostream &os,const pair &a){ return os << a.first << ' ' << a.second; } template inline ostream &operator<<(ostream &os,const tuple &a){ return os << get<0>(a) << ' ' << get<1>(a) << ' ' << get<2>(a); } template inline ostream &operator<<(ostream &os,const tuple &a){ return os << get<0>(a) << ' ' << get<1>(a) << ' ' << get<2>(a) << ' ' << get<3>(a); } template inline ostream &operator<<(ostream &os,const vector &a){ for (ll i=0; i<(ll)a.size(); i++) os<<(i>0?" ":"")<(system_clock::now()-st).count()/1000;} } timeget; template struct mll_{ using Int = long long; using ll = long long; ll val_=0; /*---- utility ----*/ mll_ &norm(){ return normR().normS(); }//正規化 mll_ &normR(){ val_%=MOD; return *this; }//剰余正規化のみ mll_ &normS(){ if (val_<0) val_+=MOD; return *this; }//正負正規化のみ mll_ &normP(){ if (val_>=MOD) val_-=MOD; return *this; }//加算時正規化 mll_ &invsg(){ val_=-val_; return normS(); }//正負反転 ll modinv(int a){//a^-1 mod MOD int ypre=0,y=1,apre=MOD; while (a>1){ int t=apre/a; apre-=a*t,swap(a,apre); ypre-=y*t,swap(y,ypre); } return y<0 ? y+MOD : y; } /*---- I/F ----*/ mll_(){} mll_(ll v): val_(v){ norm(); } mll_(ll v,bool b): val_(v){} //正規化無のコンストラクタ Int val()const{ return (Int)val_; } bool isnone() const { return val_==-1; } //true:値なし mll_ &none() { val_=-1; return *this; } //値なしにする mll_ &inv(){ val_=modinv((int)val_); return *this; } mll_ &operator+=(mll_ b){ val_+=b.val_; return normP(); } mll_ &operator-=(mll_ b){ val_-=b.val_; return normS(); } mll_ &operator*=(mll_ b){ val_*=b.val_; return normR(); } mll_ &operator/=(mll_ b){ return *this*=b.inv(); } mll_ &operator+=(ll b){ return *this+=mll_(b); } mll_ &operator-=(ll b){ return *this-=mll_(b); } mll_ &operator*=(ll b){ return *this*=mll_(b); } mll_ &operator/=(ll b){ return *this/=mll_(b); } mll_ operator-()const{ return mll_(*this).invsg(); } mll_ operator+(mll_ b)const{ return mll_(*this)+=b; } mll_ operator-(mll_ b)const{ return mll_(*this)-=b; } mll_ operator*(mll_ b)const{ return mll_(*this)*=b; } mll_ operator/(mll_ b)const{ return mll_(*this)/=b; } mll_ operator+(ll b)const{ return mll_(*this)+=b; } mll_ operator-(ll b)const{ return mll_(*this)-=b; } mll_ operator*(ll b)const{ return mll_(*this)*=b; } mll_ operator/(ll b)const{ return mll_(*this)/=b; } friend mll_ operator+(ll a,mll_ b){ return b+a; } friend mll_ operator-(ll a,mll_ b){ return -b+a; } friend mll_ operator*(ll a,mll_ b){ return b*a; } friend mll_ operator/(ll a,mll_ b){ return mll_(a)/b; } bool operator==(mll_ b)const{ return val_==b.val_; } bool operator!=(mll_ b)const{ return val_!=b.val_; } bool operator==(ll b)const{ return *this==mll_(b); } bool operator!=(ll b)const{ return *this!=mll_(b); } friend bool operator==(ll a,mll_ b){ return mll_(a)==b; } friend bool operator!=(ll a,mll_ b){ return mll_(a)!=b; } friend ostream &operator<<(ostream &os,mll_ a){ return os << a.val_; } friend istream &operator>>(istream &is,mll_ &a){ return is >> a.val_; } mll_ pow(ll k)const{ mll_ ret(1,false),a(*this); for (; k>0; k>>=1,a*=a) if (k&1)ret*=a; return ret; } static constexpr int mod() { return MOD; } //enum{ modll=MOD }; }; template struct Vector: vector{ using Int = long long; using vT=vector; using cvT=const vector; using cT=const T; using vT::vT; //親クラスのコンストラクタの隠蔽を回避 using vT::begin,vT::end,vT::insert,vT::erase; auto it(Int i){ return begin()+i; } auto it(Int i)const{ return begin()+i; } Vector(cvT& b):vT(b){} Vector(vT&& b):vT(move(b)){} Vector(int n,cT& x):vT(n,x){}// ┬ 型推論のためラッパー Vector(long long n,cT& x):vT(n,x){} template Vector(const Vector& b):vT(b.begin(),b.end()){} template Vector(const vector& b):vT(b.begin(),b.end()){} Vector(Int n,T s,T d){ iota(n,s,d); } Vector(Int n,function g):vT(n){ for(Int i=0;i &b){ return *this+=(cvT&)b; } Vector &operator-=(const Vector &b){ return *this-=(cvT&)b; } Vector &operator*=(const Vector &b){ return *this*=(cvT&)b; } Vector &operator/=(const Vector &b){ return *this/=(cvT&)b; } Vector &operator%=(const Vector &b){ return *this%=(cvT&)b; } Vector operator+(cvT &b){ return Vector(*this)+=b; } Vector operator-(cvT &b){ return Vector(*this)-=b; } Vector operator*(cvT &b){ return Vector(*this)*=b; } Vector operator/(cvT &b){ return Vector(*this)/=b; } Vector operator%(cvT &b){ return Vector(*this)%=b; } Vector operator+(const Vector &b){ return Vector(*this)+=b; } Vector operator-(const Vector &b){ return Vector(*this)-=b; } Vector operator*(const Vector &b){ return Vector(*this)*=b; } Vector operator/(const Vector &b){ return Vector(*this)/=b; } Vector operator%(const Vector &b){ return Vector(*this)%=b; } template Vector &operator+=(S x){ for(T &e: *this) e+=x; return *this; } template Vector &operator-=(S x){ for(T &e: *this) e-=x; return *this; } template Vector &operator*=(S x){ for(T &e: *this) e*=x; return *this; } template Vector &operator/=(S x){ for(T &e: *this) e/=x; return *this; } template Vector &operator%=(S x){ for(T &e: *this) e%=x; return *this; } template Vector operator+(S x)const{ return Vector(*this)+=x; } template Vector operator-(S x)const{ return Vector(*this)-=x; } template Vector operator*(S x)const{ return Vector(*this)*=x; } template Vector operator/(S x)const{ return Vector(*this)/=x; } template Vector operator%(S x)const{ return Vector(*this)%=x; } Vector &operator--(int){ return *this-=1; } Vector &operator++(int){ return *this+=1; } Vector operator-()const{ return Vector(*this)*=-1; } template friend Vector operator-(S x,const Vector &a){ return -a+=x; } T& at(Int i){ assert(i>=0); if(n()<=i)vT::resize(i+1); return vT::operator[](i); } Vector slice(Int l,Int r,Int d=1)const{ Vector ret; for(Int i=l;(d>0&&i<=r)||(d<0&&r<=i);i+=d) ret.push_back((*this)[i]); return ret; } Int size()const{ return (Int)vT::size(); } Int n()const{ return size(); } Vector &push_back(cT& x,Int n=1){ for(Int i=0;iinsert(0,x,n); return *this; } Vector &pop_front(Int n=1){ erase(0,n-1); return *this; } T pull_back(){ T x=move(vT::back()); vT::pop_back(); return x; } T pull_front(){ T x=move(vT::front()); erase(0); return x; } Vector &insert(Int i,cT& x,Int n=1){ insert(it(i),n,x); return *this; } Vector &insert(Int i,cvT& b){ insert(it(i),b.begin(),b.end()); return *this; } Vector &erase(Int i){ erase(it(i)); return *this; } Vector &erase(Int l,Int r){ erase(it(l),it(r+1)); return *this; } Vector &erase(const Vector &idxs){ for (Int I=0; In(); copy(it(l),it(r),it(l-I-1));//[l,r)を前にI+1個ずらす } vT::resize(this->n()-idxs.n()); return *this; } Vector &eraseall(cT& x){ return eraseall(0,size()-1,x); } Vector &eraseall(Int l,Int r,cT& x){ erase(remove(it(l),it(r+1),x),it(r+1)); return *this; } template Vector &eraseif(Pr pr){ return eraseif(0,size()-1,pr); } template Vector &eraseif(Int l,Int r,Pr pr){ erase(remove_if(it(l),it(r+1),pr),it(r+1)); return *this; } Vector &concat(cvT &b,Int n=1){ cvT B = (&b==this) ? *this : vT{}; for(int i=0;iinsert(size(),(&b==this)?B:b); return *this; } Vector repeat(Int n){ return Vector{}.concat(*this,n); } Vector &reverse(Int l=0,Int r=-1){ r+=r<0?size():0; std::reverse(it(l),it(r+1)); return *this; } Vector &rotate(Int m){ return rotate(0,size()-1,m); } Vector &rotate(Int l,Int r,Int m){ std::rotate(it(l),it(m),it(r+1)); return *this; } Vector &sort(Int l=0,Int r=-1){ r+=r<0?size():0; std::sort(it(l),it(r+1)); return *this; } Vector &rsort(Int l=0,Int r=-1){ return sort(l,r).reverse(l,r); } template Vector &sort(Pr pr){ return sort(0,size()-1,pr); } template Vector &sort(Int l,Int r,Pr pr){ std::sort(it(l),it(r+1),pr); return *this; } template Vector &sortbykey(Int l=0,Int r=-1){ r+=r<0?size():0; sort(l,r,[](cT &x,cT &y){return get(x)(y);}); return *this; } Vector &uniq(){ erase(unique(begin(),end()),end()); return *this; } Vector &sortq(){ return sort().uniq(); } Vector &fill(cT& x){ return fill(0,size()-1,x); } Vector &fill(Int l,Int r,cT& x){ std::fill(it(l),it(r+1),x); return *this; } Vector ©(Int i,cvT &b,Int n=1){//A[i]スタートでbをn回分コピー for (int t=0; t=size()) return *this; if (i>=0) (*this)[i]=b[j]; i++; } return *this; } template Vector &iota(Int n,T s=0,S d=1){ vT::resize(n); if(n==0) return *this; (*this)[0]=s; for(int i=1;i Int countif(Pr pr)const{ return countif(0,size()-1,pr); } template Int countif(Int l,Int r,Pr pr)const{ return Int(count_if(it(l),it(r+1),pr)); } Int find(cT& x)const{ return find(0,size()-1,x); } Int find(Int l,Int r,cT& x)const{ return Int(std::find(it(l),it(r+1),x)-begin()); } Int rfind(cT& x)const{ return rfind(0,size()-1,x); } Int rfind(Int l,Int r,cT& x)const{ for (int i=r;i>=l;--i) if ((*this)[i]==x) return i; return l-1; } template Int findif(Pr pr)const{ return findif(0,size()-1,pr); } template Int findif(Int l,Int r,Pr pr)const{ return Int(find_if(it(l),it(r+1),pr)-begin()); } Vector findall(cT& x)const{ return findall(0,size()-1,x); } Vector findall(Int l,Int r,cT& x)const{ return findallif(l,r,[&](cT& y){return y==x;}); } template Vector findallif(Pr pr)const{ return findallif(0,size()-1,pr); } template Vector findallif(Int l,Int r,Pr pr)const{ Vector ret; for(Int i=l;i<=r;++i) if(pr((*this)[i])) ret.push_back(i); return ret; } Int flooridx(cT& x)const{ return Int(upper_bound(begin(),end(),x)-begin()-1); } Int ceilidx(cT& x)const{ return Int(lower_bound(begin(),end(),x)-begin()); } Int leftnmof(cT& x)const{ return flooridx(x)+1; } Int rightnmof(cT& x)const{ return size()-ceilidx(x); } bool contains(cT& x)const{ Int i=flooridx(x); return i>=0 && (*this)[i]==x; } template Int flooridx(cT& x,Pr pr)const{ return Int(upper_bound(begin(),end(),x,pr)-begin()-1); } template Int ceilidx(cT& x,Pr pr)const{ return Int(lower_bound(begin(),end(),x,pr)-begin()); } template Int leftnmof(cT& x,Pr pr)const{ return flooridx(x,pr)+1; } template Int rightnmof(cT& x,Pr pr)const{ return size()-ceilidx(x,pr); } template bool contains(cT& x,Pr pr)const{ Int i=flooridx(x,pr); return i>=0 && (*this)[i]==x; } template using VV = Vector>; template using sVV = vector>; template using VVV = Vector>; template using sVVV = vector>; template using VVVV = Vector>; template using sVVVV = vector>; template using VVVVV = Vector>; template using sVVVVV = vector>; auto tostd()const{ return tov(*this); } template static vector tov(const Vector&v){ return v; } template static sVV tov(const VV &v){ sVV ret; for(auto&& e:v) ret.push_back(e); return ret; } template static sVVV tov(const VVV &v){ sVVV ret; for(auto&& e:v) ret.push_back(e.tostd()); return ret; } template static sVVVV tov(const VVVV &v){ sVVVV ret; for(auto&& e:v) ret.push_back(e.tostd()); return ret; } template static sVVVVV tov(const VVVVV &v){ sVVVVV ret; for(auto&& e:v) ret.push_back(e.tostd()); return ret; } }; #if 1 #define MODLL (1000000007LL) #else #define MODLL (998244353LL) #endif using mll = mll_; //using mll = fraction; namespace SolvingSpace{ template using vector = Vector; using vll=vector< ll>; using vmll=vector< mll>; using vdd=vector< dd>; using vvll=vector< vll>; using vvmll=vector< vmll>; using vvdd=vector< vdd>; using vvvll=vector< vvll>; using vvvmll=vector< vvmll>; using vvvdd=vector< vvdd>; using vvvvll=vector; using vvvvmll=vector; using vvvvdd=vector; using vpll=vector< pll>; using vtll=vector< tll>; using vqll=vector< qll>; using vvpll=vector< vpll>; using vvtll=vector< vtll>; using vvqll=vector< vqll>; using vss=vector; template vector cinv(ll nm){ return vector(nm,[](ll i){ (void)i; return cin1(); }); } template vector> cinvv(ll H,ll W){ return vector>(H,[&](ll i){ (void)i; return cinv(W); }); } /*■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■*/ namespace graphSpace{ using Int=long long; using ll=long long; //FirstType Tがpair,tupleのとき第一要素の型、それ以外のときT template concept IsTpl=requires{ typename tuple_size::type; }; template struct FirstTypeSub { using type=T; }; template struct FirstTypeSub { using type=tuple_element_t<0,T>; }; template using FirstType = typename FirstTypeSub::type; template struct edge{ using CostType=FirstType; int to=-1; int idx_=-1;//辺の通し番号 T data_=T(); //long long, pair, tuple等 第1要素がcost edge(){} edge(Int to,T data,Int idx=-1): to((int)to),idx_((int)idx),data_(data){} operator Int()const{ return (Int)to; } Int operator=(Int v){ this->to=(int)v; return v; } int &idx(){ return idx_; } Int idx()const{ return (Int)idx_; } CostType &cost(){ if constexpr (IsTpl){ return std::get<0>(data_); } else return data_; } const CostType &cost()const{ return const_cast(this)->cost(); } template auto &val(){ return std::get(data_); } template const auto &val()const{ return std::get(data_); } T &data(){ return data_; } const T &data()const{ return data_; } bool operator<(const edge &e)const{ return to==e.to ? idx_ struct graphHelper{ vector>> to; ll edgeIdxLast=-1;//最後に追加した辺の通し番号 bool edgeSorted=false; /*---- 準備関連I/F ----*/ graphHelper(){} graphHelper(Int N):to(N){} graphHelper(Int N,const vector> &uvc,bool isDirected) : to(N){ build(uvc,isDirected); } graphHelper(Int N,const vector> &uv,bool isDirected,T cost=T(1)) : to(N){ build(uv,isDirected,cost); } void build(const vector> &uvc,bool isDirected){ for (auto [u,v,c]:uvc){ ll ei=newEdgeIdx(); to[u].emplace_back(v,c,ei); if (!isDirected) to[v].emplace_back(u,c,ei); } } void build(const vector> &uv,bool isDirected,T cost=T(1)){ for (auto [u,v]:uv){ ll ei=newEdgeIdx(); to[u].emplace_back(v,cost,ei); if (!isDirected) to[v].emplace_back(u,cost,ei); } } void sortedge(){ for (auto &v:to) sort(v.begin(),v.end()); edgeSorted=true; } /*---- 操作・アクセスI/F ----*/ vector>> &get(){ return to; } Int size()const{ return (Int)to.size(); } bool existarc(Int u,Int v){ for (const auto &eg:to[u]) if (Int(eg)==v) return true; return false; } bool existarcS(Int u,Int v){ assert(edgeSorted); auto it=lower_bound(to[u].begin(),to[u].end(),edge(v,T(),-1)); return !(it==to[u].end() || Int(*it)!=v); } edge &getarc(Int u,Int v){ vector> &vec=to[u]; auto it=find_if(vec.begin(),vec.end(),[&](auto &eg){return eg==v; }); assert(it!=vec.end()); return *it; } edge &getarcS(Int u,Int v){ assert(edgeSorted); auto it=lower_bound(to[u].begin(),to[u].end(),edge(v,T(),-1)); assert(!(it==to[u].end() || Int(*it)!=v)); return *it; } Int addnode(){ to.resize(size()+1); return size()-1; } void addnode(Int num){ to.resize((Int)to.size()+num); } void addarc(Int u,Int v,T cost=T(1)){ to[u].emplace_back(v,cost,newEdgeIdx()); } void addedge(Int u,Int v,T cost=T(1)){ ll ei=newEdgeIdx(); to[u].emplace_back(v,cost,ei); to[v].emplace_back(u,cost,ei); } void erasenode(Int v,bool isDir){ if (isDir){ to[v].clear(); //出辺全削除 for (ll u=0; u us; for (auto&& eg: to[v]) us.push_back(ll(eg)); //隣接頂点列挙 sort(us.begin(),us.end()); us.erase(unique(us.begin(),us.end()),us.end()); //重複削除 for (auto&& u: us) eraseArcAll(u,v); //入辺全削除 to[v].clear(); //出辺全削除 } } void eraseedge(Int u,Int v,bool isall=true){ if (isall){ eraseArcAll(u,v); eraseArcAll(v,u); } else{ int idx=eraseArc1(u,v); eraseArcIdx(v,u,idx); } } void erasearc(Int u,Int v,bool isall=true){ if (isall) eraseArcAll(u,v); else eraseArc1 (u,v); } void dump(bool isDirected,bool withCost,bool zeroIndexed=false){ multiset> egs;// for (ll v=0; v<(ll)to.size(); ++v) for (auto&& eg: to[v]){ egs.emplace(eg.idx(),v,ll(eg),eg.data()); } vector> abw; while (egs.size()){ auto it=egs.begin(); auto [idx,v,u,data]=*it; abw.emplace_back(v,u,data); egs.erase(it); if (!isDirected){ //無向辺の場合、反対向きの辺を消す auto itrev=egs.find({idx,u,v,data}); assert(itrev!=egs.end()); egs.erase(itrev); } } cout << to.size() << ' ' << abw.size() << '\n'; for (auto&&[a,b,w]:abw){ cout << a+1-zeroIndexed << ' ' << b+1-zeroIndexed; if (withCost) cout << ' ' << w; cout << '\n'; } } private: ll newEdgeIdx(){ return ++edgeIdxLast; } void eraseArcAll(Int u,Int v){//有向辺u→vを全削除 to[u]内のvを全削除 vector> &vec=to[u]; auto it=remove_if(vec.begin(),vec.end(),[&](auto &eg){return eg==v; }); vec.erase(it,vec.end()); } int eraseArc1(Int u,Int v){//有向辺u→vを1つ削除 @return 削除した辺のidx vector> &vec=to[u]; auto it=find_if(vec.begin(),vec.end(),[&](auto &eg){return eg==v; }); assert(it!=vec.end()); int idx=it->idx(); vec.erase(it); return idx; } void eraseArcIdx(Int u,Int v,int idx){//辺のidxを指定して削除 vector> &vec=to[u]; auto it=find_if(vec.begin(),vec.end(),[&](auto &eg){ return eg==v && eg.idx()==idx; }); assert(it!=vec.end()); vec.erase(it); } }; } using graphSpace::edge; using graphSpace::graphHelper; /* 重み無しグラフは重み1の重み付きグラフとして扱う - ---- N頂点0辺グラフ ---- graphHelper G(N); graphHelper
G(N); graphHelper> G(N); . ↑辺に乗せる値(重み等)の型 省略時ll - ---- N頂点辺指定 ---- . {,…}↓ ↓true:有向、false:無向 graphHelper G(N,uv,false); //重み無しグラフ(重みall1) graphHelper G(N,uv,false,5ll); //↑の重みをall5に指定 graphHelper G(N,uvc,false); //重み付きグラフ . ↑{,…} - ---- 操作 ---- ll v=G.addnode(); //頂点1つ追加 v:追加された頂点番号 G.addnode(n); //頂点n個追加 G.addarc(u,v); //有向辺u→vを張る G.addedge(u,v); //無向辺u→vを張る G.addedge(u,v,c); //重みcで張る G.addedge(u,v,{c,a}); //辺に複数の値を乗せる例 G.erasenode(v,false); //vにつながる辺を全削除 無向グラフ G.erasenode(v,true); //vにつながる辺を全削除 有向グラフ O(N) G.erasearc(u,v); //有向辺u→vを全て削除 G.erasearc(u,v,false); //有向辺u→vを1つ削除 G.eraseedge(u,v); //無向辺u-vを全て削除 G.eraseedge(u,v,false); //無向辺u-vを1つ削除 G.existarc(u,v); //true:辺uv有 auto &eg=G.getarc(u,v); //辺uv取得 ないときは落ちる G.dump(false,false); .true:有向↑ ↑true:重み有 - ---- 辺クラス内部のアクセス ---- auto &to=G.to; //グラフ auto &eg=to[v][i]; //辺取得 auto [c,va]=eg.data(); //辺に乗せた値全て ll cost =eg.cost(); //コスト(=辺に乗せた値の第1要素) ll val =eg.val<1>();//辺に乗せた値の第2要素 ll ei =eg.idx(); //辺index 追加した順に振られる eg.cost()=c, eg.val<1>()=va, eg.idx()=i, eg.data()={c,va}; //代入も可能 - ---- 辺ソート時のみの処理 ---- G.sortedge(); //辺を頂点番号順にソート auto &eg=G.getarcS(u,v); //辺uv取得 ないときは落ちる bool b=G.existarcS(u,v); //true:辺uv有 G.getarcS(u,v).cost()=cost; //有向辺uvのコスト変更 G.getarcS(u,v).cost()=G.getarcS(v,u).cost()=cost; //無向辺uvの 〃 */ namespace BFSspace{ using Int=long long; using ll=long long; template vector bfs(vector> &to,ll s,Int inf){ vector dist(to.size(),inf); queue Q; dist[s] = 0; Q.push(s); while (!Q.empty()){ ll v = Q.front(); Q.pop(); for (ll u : to[v]) if (chmin(dist[u],dist[v]+1)) Q.push(u); } return dist; } template vector getpath(vector &dist,ll g,vector> &rto){ vector path={(Int)g}; ll v=g; while (dist[v]!=0){ for (ll u : rto[v]){ if (dist[u]==dist[v]-1){ v=u; break; } } path.push_back(v); } reverse(path.begin(),path.end()); return path; } } using BFSspace::bfs; using BFSspace::getpath; /* - ---- bfs ---- vll dist = bfs(to,s,INF); . ↑dist[v]:sからvまでの距離 到達できないノードはINF - ---- sからgまでの最短パス ---- vll path=getpath(dist,g,to); vll path=getpath(dist,g,rto); //有向グラフのときはrtoを指定 . ↑path[0]=s, path.back()=g */ void cin2solve() { auto [N,M]=cins(); auto abc=cinv>(M); for (auto&&[a,b,c]:abc) a--,b--; /* ≠を1つ以下使って、最短でNまでいく */ graphHelper Geq(N); for (auto&&[a,b,c]:abc){ if (c==1) Geq.addedge(a,b); } auto &toeq=Geq.to; vll dist1 = bfs(toeq,0,INF); vll distN = bfs(toeq,N-1,INF); if (dist1[N-1]INF/2){ cout << "Unknown" << '\n'; } else{ cout << "Different" << '\n'; cout << ans << '\n'; } } return; } }//SolvingSpace ////////////////////////////////////////// int main(){ #if defined(RANDOM_TEST) SolvingSpace::cin2solve(); SolvingSpace::generand(); #else #if 0 //SolvingSpace::labo();' SolvingSpace::cin2solve(); #else ll t; cin >> t; rep(i,0,t-1){ SolvingSpace::cin2solve(); } #endif #endif cerr << timeget() <<"ms"<< '\n'; return 0; }