#include using namespace std; class UnionFind{ private: vector par,siz; public: UnionFind(int N){ par.resize(N,-1); siz.resize(N,1); } int root(int x){ //連結成分の代表頂点を返す. if(par.at(x) == -1) return x; else return par.at(x) = root(par.at(x)); } bool unite(int u, int v){ //u,vを連結する 連結してた->false,した->trueを返す. u = root(u),v = root(v); if(u == v) return false; if(siz.at(u) < siz.at(v)) swap(u,v); //Union by size. par.at(v) = u; siz.at(u) += siz.at(v); return true; } bool issame(int u, int v){ //同じ連結成分ならtrue. if(root(u) == root(v)) return true; else return false; } int size(int pos){return siz.at(root(pos));} //posの連結成分の大きさを返す. }; vector BFS(vector> &Graph,int start){ int N = Graph.size(); vector ret(N,-1); queue Q; ret.at(start) = 0,Q.push(start); while(Q.size()){ int pos = Q.front(); Q.pop(); for(auto to : Graph.at(pos)){ if(ret.at(to) != -1) continue; ret.at(to) = ret.at(pos)+1; Q.push(to); } } return ret; } class SpecialSparseTable{ //LCA専用. private: int log = 0; pair op(pair &a,pair &b){return min(a,b);} pair add(pair &a,pair &b){return {a.first+b.first,a.second+b.second};} vector check,belong,Second; vector> Add; vector>>> Group; vector>> table; void maketable(vector> &A){ int n = A.size(); table.resize(n+1); check.resize(n+1); int p2 = 1; for(int i=1; i<=n; i++){ if(i == p2) check.at(i) = i,p2 *= 2; else check.at(i) = check.at(i-1); } table.at(1) = A; for(int i=2; i<=n; i*=2){ table.at(i).resize(n); for(int k=0; k<=n-i; k++) table[i][k] = op(table[i>>1][k],table[i>>1][k+(i>>1)]); } } void makeGroup(vector> &A){ int loop = 1<<(log-1); Group.resize(loop,vector>>(log,vector>(log))); for(int i=0; i now(1); for(int k=0; k now.at(r)) mina = now.at(r),pos = r; Group.at(i).at(l).at(r) = {mina,pos}; } } } } pair tablerange(int l,int r){//[L,R)だよ. int len = r-l,pos = check.at(len); return op(table.at(pos).at(l),table.at(pos).at(r-pos)); } public: void make(vector> &A){ int p2 = 1,n = A.size(); while(p2 < n) p2 *= 2,log++; log = max(1,(log+1)/2); vector> sepa; for(int i=0; i now = {1001001001,-1}; for(int k=i; k A.at(k)) now = {A.at(k).first,k}; } Add.push_back({A.at(i).first,i}); sepa.push_back(now); belong.push_back(g); } maketable(sepa); makeGroup(A); } int rangeans(int l,int r){ //[l,r)! int l2 = (l+log-1)/log,r2 = r/log; pair mind = {1001001001,-1}; if(l2 > r2) mind = add(Group[belong[r2]][l%log][(r-1)%log],Add[r2]); else{ if(l2 < r2) mind = tablerange(l2,r2); if(l%log) mind = min(mind,add(Group[belong[l2-1]][l%log][log-1],Add[l2-1])); if(r%log) mind = min(mind,add(Group[belong[r2]][0][(r-1)%log],Add[r2])); } return Second.at(mind.second); } }; class LCA{ private: vector dist,in,out; SpecialSparseTable ST; public: void make1(vector &P){// p0=-1でp1以降だけ int r = 0; vector> G(P.size()+1); for(int i=0; i &P){//pi=-1 iは固定されていない. int r = -1; vector> G(P.size()); for(int i=0; i> &Graph,int root){ //直接グラフを渡す. int t = 0,dep = 0,n = Graph.size(),pos = root; dist.resize(n),in.resize(n),out.resize(n); vector> depth; vector Itr(n,-1),P(n,-1); while(pos != -1){ depth.push_back({dep,pos}); if(++Itr.at(pos) == 0) in.at(pos) = t; int to = P.at(pos); if(Itr.at(pos) == Graph.at(pos).size()) out.at(pos) = ++t; else{ to = Graph.at(pos).at(Itr.at(pos)); if(to == P.at(pos)){ Itr.at(pos)++; if(Itr.at(pos) == Graph.at(pos).size()) out.at(pos) = ++t; else to = Graph.at(pos).at(Itr.at(pos)); } } if(to != P.at(pos)) dist.at(to) = dist.at(pos)+1,P.at(to) = pos,t++,dep++; else dep--; pos = to; } ST.make(depth); } int lca(int u,int v){ int tu = in.at(u),tv = in.at(v); if(tu > tv) swap(tu,tv); return ST.rangeans(tu,tv+1); } int twodist(int u,int v){return dist.at(u)+dist.at(v)-2*dist.at(lca(u,v));} int onedist(int u){return dist.at(u);} }; int main(){ ios_base::sync_with_stdio(false); cin.tie(nullptr); int N,M,S,G; cin >> N >> M >> S >> G,S--,G--; vector> edge(M); vector> Graph(N); for(auto &[u,v] : edge){ cin >> u >> v; u--; v--; Graph.at(u).push_back(v); Graph.at(v).push_back(u); } auto dist = BFS(Graph,S); if(dist.at(G) == -1){cout << "-1\n"; return 0;} vector P(N,-1); int n = 0; for(int i=0; i> left; UnionFind Z(n); Graph.assign(n,vector(0)); for(auto [u,v] : edge){ if(P.at(u) == -1) continue; u = P.at(u),v = P.at(v); if(Z.unite(u,v)){ Graph.at(u).push_back(v); Graph.at(v).push_back(u); } else left.push_back({u,v}); } set> OK; LCA L; L.make3(Graph,S); vector V(n); for(auto [u,v] : left){ V.at(u)++,V.at(v)++; V.at(L.lca(u,v)) -= 2; OK.insert({u,v}),OK.insert({v,u}); } auto dfs = [&](auto dfs,int pos,int back) -> int { int ret = V.at(pos); for(auto to : Graph.at(pos)){ if(to == back) continue; int kid = dfs(dfs,to,pos); ret += kid; if(kid) OK.insert({pos,to}),OK.insert({to,pos}); } return ret; }; dfs(dfs,S,-1); for(auto [u,v] : left){ Graph.at(u).push_back(v); Graph.at(v).push_back(u); } dist = BFS(Graph,S); vector dp(n); queue Q; Q.push(S); vector already(n); already.at(S) = true; while(Q.size()){ int pos = Q.front(); Q.pop(); for(auto to : Graph.at(pos)) if(dist.at(to) == dist.at(pos)+1){ if(OK.count({pos,to})) dp.at(to) = max(dp.at(to),dp.at(pos)+1); else dp.at(to) = max(dp.at(to),dp.at(pos)); if(already.at(to)) continue; already.at(to) = true,Q.push(to); } } cout << dp.at(G) << endl; }