#include using namespace std; struct HLD1{ //1.頂点のみパターン. int n = 0,tim = 0; vector dist,in,out,siz,head,par,ord; HLD1(vector> &Graph,int Root = 0):n(Graph.size()),dist(n),in(n),out(n),siz(n),head(n),par(n),ord(n){ iota(head.begin(),head.end(),0); auto dfs1 = [&](auto dfs1,int pos,int back,int d) -> int { par.at(pos) = back,dist.at(pos) = d; int maxsiz = 0,big = -1,idx = -1,ret = 1; for(auto to : Graph.at(pos)){ idx++; if(to == back) continue; int kid = dfs1(dfs1,to,pos,d+1); ret += kid; if(maxsiz < kid) maxsiz = kid,big = idx; } if(big > -1) swap(Graph.at(pos).at(0),Graph.at(pos).at(big)); return siz.at(pos) = ret; }; int time = 0; auto dfs2 = [&](auto dfs2,int pos,int back) -> void { ord.at(time) = pos,in.at(pos) = time++; if(Graph.at(pos).size() > 1) head.at(Graph.at(pos).at(0)) = head.at(pos); for(auto to : Graph.at(pos)) if(to != back) dfs2(dfs2,to,pos); out.at(pos) = time; }; dfs1(dfs1,Root,-1,0),dfs2(dfs2,Root,-1); } vector> findpath(int u,int v){ //O(logN). //dfs行きがけ順に並べた頂点のセグ木の区間を返す. //行きがけ順はrep(0-n)give[in[i]]=A[i]. //交換法則が成り立たない時は修正必須. vector> ret; while(head.at(u) != head.at(v)){ if(dist.at(head.at(u)) > dist.at(head.at(v))) swap(u,v); ret.push_back({in.at(head.at(v)),in.at(v)+1}); v = par.at(head.at(v)); } if(in.at(u) > in.at(v)) swap(u,v); ret.push_back({in.at(u),in.at(v)+1}); return ret; } pair subtree(int u){return {in.at(u),out.at(u)};} int lca(int u,int v){ //O(logN). int hu = head.at(u),hv = head.at(v); while(hu != hv){ if(dist.at(hu) < dist.at(hv)) v = par.at(hv),hv = head.at(v); else u = par.at(hu),hu = head.at(u); } if(dist.at(u) <= dist.at(v)) return u; else return v; } int jump(int u,int v,int k){ //u->vパスでuからk個進んだ頂点 O(logN). int l = lca(u,v); if(k <= dist.at(u)-dist.at(l)) return la(u,k); k -= dist.at(u)-dist.at(l); if(k <= dist.at(v)-dist.at(l)) return la(v,dist.at(v)-dist.at(l)-k); return -1; //パス長 class Cumulative{ //1次元. private: T op(T a,T b){return {a.first+b.first,a.second+b.second};} T inv(T a){return {0,0};} //ない場合はスルー->rangeans使用不可. T e(){return {0,0};} int n; vector L,R; public: Cumulative(){} Cumulative(vector &A){make(A);} void make(vector &A){ L = A,R = A; n = A.size(); for(int i=1; i=0; i--) R.at(i) = op(R.at(i),R.at(i+1)); } T rangeans(int l,int r){ //[l,r]だよL<0も許容 逆元はいる. if(l > r || r < 0) return e(); T ret = L.at(r); if(l > 0) ret = op(ret,inv(L.at(l-1))); return ret; } T skipone(int pos){ //0<=pos 0) ret = L.at(pos-1); if(pos != n-1) ret = op(ret,R.at(pos+1)); return ret; } T skiprange(int l,int r){//l<=r. T ret = e(); if(l > 0) ret = L.at(l-1); if(r != n-1) ret = op(ret,R.at(r+1)); return ret; } T get(int pos){return L.at(pos);} vector allA(){return L;} }; int main(){ ios_base::sync_with_stdio(false); cin.tie(nullptr); auto f = [&](vector> Graph,vector C,vector> AB) -> long long { int N = Graph.size(); if(N == 1) return 0; HLD1 H(Graph); long long ret = 1e18; vector par(N,-1); vector>> kid(N); { auto dfs = [&](auto dfs,int pos,int back) -> pair { int n = Graph.at(pos).size(); kid.at(pos).resize(n); long long ret1 = C.at(pos),ret2 = 0; for(int i=0; i take) -> void { if(back != -1) kid.at(pos).at(par.at(pos)) = take; Cumulative Z(kid.at(pos)); int n = Graph.at(pos).size(); ret = min(ret,Z.get(n-1).second); for(int i=0; i> N >> M >> q; vector> Graph(N); for(int i=0; i> u >> v; u--; v--; Graph.at(u).push_back(v); Graph.at(v).push_back(u); } vector> Ps; vector belong(N,-1); queue Q; for(int i=0; i P; while(Q.size()){ int pos = Q.front(); Q.pop(); P.push_back(pos); for(auto to : Graph.at(pos)) if(belong.at(to) == -1) belong.at(to) = belong.at(i),Q.push(to); } Ps.push_back(P); } vector> Query(N); while(q--){ int a,b; cin >> a >> b,a--,b--; Query.at(a).push_back(b); Query.at(b).push_back(a); } long long answer = 0; vector Pos(N,-1); for(auto &P : Ps){ int n = P.size(); vector C(n); vector> AB; vector> G(n); for(int i=0; i