#![allow(unused_imports)] #![allow(non_snake_case, unused)] use std::cmp::*; use std::collections::*; use std::ops::*; macro_rules! eprint { ($($t:tt)*) => {{ use ::std::io::Write; let _ = write!(::std::io::stderr(), $($t)*); }}; } macro_rules! eprintln { () => { eprintln!(""); }; ($($t:tt)*) => {{ use ::std::io::Write; let _ = writeln!(::std::io::stderr(), $($t)*); }}; } macro_rules! dbg { ($v:expr) => {{ let val = $v; eprintln!("[{}:{}] {} = {:?}", file!(), line!(), stringify!($v), val); val }} } macro_rules! mat { ($($e:expr),*) => { Vec::from(vec![$($e),*]) }; ($($e:expr,)*) => { Vec::from(vec![$($e),*]) }; ($e:expr; $d:expr) => { Vec::from(vec![$e; $d]) }; ($e:expr; $d:expr $(; $ds:expr)+) => { Vec::from(vec![mat![$e $(; $ds)*]; $d]) }; } macro_rules! ok { ($a:ident$([$i:expr])*.$f:ident()$(@$t:ident)*) => { $a$([$i])*.$f($($t),*) }; ($a:ident$([$i:expr])*.$f:ident($e:expr$(,$es:expr)*)$(@$t:ident)*) => { { let t = $e; ok!($a$([$i])*.$f($($es),*)$(@$t)*@t) } }; } pub fn readln() -> String { let mut line = String::new(); ::std::io::stdin().read_line(&mut line).unwrap_or_else(|e| panic!("{}", e)); line } macro_rules! read { ($($t:tt),*; $n:expr) => {{ let stdin = ::std::io::stdin(); let ret = ::std::io::BufRead::lines(stdin.lock()).take($n).map(|line| { let line = line.unwrap(); let mut it = line.split_whitespace(); _read!(it; $($t),*) }).collect::>(); ret }}; ($($t:tt),*) => {{ let line = readln(); let mut it = line.split_whitespace(); _read!(it; $($t),*) }}; } macro_rules! _read { ($it:ident; [char]) => { _read!($it; String).chars().collect::>() }; ($it:ident; [u8]) => { Vec::from(_read!($it; String).into_bytes()) }; ($it:ident; usize1) => { $it.next().unwrap_or_else(|| panic!("input mismatch")).parse::().unwrap_or_else(|e| panic!("{}", e)) - 1 }; ($it:ident; [usize1]) => { $it.map(|s| s.parse::().unwrap_or_else(|e| panic!("{}", e)) - 1).collect::>() }; ($it:ident; [$t:ty]) => { $it.map(|s| s.parse::<$t>().unwrap_or_else(|e| panic!("{}", e))).collect::>() }; ($it:ident; $t:ty) => { $it.next().unwrap_or_else(|| panic!("input mismatch")).parse::<$t>().unwrap_or_else(|e| panic!("{}", e)) }; ($it:ident; $($t:tt),+) => { ($(_read!($it; $t)),*) }; } pub fn main() { let _ = ::std::thread::Builder::new().name("run".to_string()).stack_size(32 * 1024 * 1024).spawn(run).unwrap().join(); } const MOD: u32 = 1_000_000_007; #[derive(Copy,Clone)] struct Pair { x: T, y: U, } impl Pair { fn new(x: T, y: U) -> Pair { Pair { x: x, y: y, } } } struct euler_tour { G: Vec>>, tour: Vec, L: Vec, R: Vec, depth: Vec, weight: Vec, n: usize, } impl euler_tour{ fn new(n: usize) -> euler_tour { euler_tour{ G: vec![vec![];n], tour: vec![], L: vec![0;n], R: vec![0;n], depth: vec![0;n], weight: vec![0;n], n: n, } } fn add_edge(&mut self, s: usize, t: usize, w: i64){ self.G[s].push(Pair::new(t,w)); self.G[t].push(Pair::new(s,w)); } fn init(&mut self, root: usize) { self.dfs(root, self.n, 0, 0); } fn dfs(&mut self, v: usize, p: usize, d: usize, w: i64){ self.tour.push(v); self.L[v] = self.tour.len()-1; self.depth[v] = d; self.weight[v] = w; for z in self.G[v].clone() { if z.x == p {continue;} self.dfs(z.x, v, d+1, w+z.y); self.tour.push(v); } self.R[v] = self.tour.len()-1; } } struct sparse_table { log_t: Vec, table: Vec>>, n: usize, } impl sparse_table { fn new() -> sparse_table{ sparse_table{ log_t: vec![], table: vec![vec![]], n: 0, } } // Pair // s: 値(最小値の検索の対象となる) // t: インデックス(任意の値) fn init(&mut self, arr: Vec>) { let n = arr.len(); let mut lt: Vec = vec![0;n+1]; for i in 2..n+1 { lt[i] = lt[i >> 1] + 1; } let sz = lt[n]; self.log_t = lt; self.table = vec![vec![Pair::new(usize::max_value(),0);sz+1];n]; self.n = n; for i in 0..n { self.table[i][0] = arr[i]; } for k in 1..n { if (1 << k) > n {break;} for i in 0..n { if i + (1 << k) > n {break;} self.table[i][k] = { let a = self.table[i][k - 1]; let b = self.table[i + (1 << (k - 1))][k - 1]; if a.x <= b.x {a} else {b} }; } } } // [s,t]の最小値を返す fn query(&mut self, s: usize, t: usize) -> Pair { let k = self.log_t[t-s+1]; let a = self.table[s][k]; let b = self.table[t + 1 - (1 << k)][k]; if a.x <= b.x {a} else {b} } } struct LCA{ euler: euler_tour, st: sparse_table, n: usize, } impl LCA{ fn new(n: usize) -> LCA { LCA{ euler: euler_tour::new(n), st: sparse_table::new(), n: n, } } fn add_edge(&mut self, s: usize, t: usize, w: i64){ self.euler.add_edge(s,t,w); } // euler tourの構築 // sparce tableの構築 fn init(&mut self) { self.euler.init(0); let sz = self.euler.tour.len(); let mut arr: Vec> = vec![Pair::new(0,0);sz]; for i in 0..sz { arr[i] = Pair::new(self.euler.depth[self.euler.tour[i]], self.euler.tour[i]); } self.st.init(arr); } // sとtのLCAを求める fn lca(&mut self, s: usize, t: usize) -> usize { self.st.query(min(self.euler.L[s],self.euler.L[t]), max(self.euler.R[s], self.euler.R[t])).y } } pub struct UnionFind { data: Vec, } impl UnionFind { /// Creates a object with n disjoint sets. `i`-th set is `{ i }`. pub fn new(n: usize) -> UnionFind { UnionFind { data: vec![-1; n] } } /// Unite a set including `x` and another set including y into one. /// Returns `true` only if they were in different set. pub fn unite(&mut self, x: usize, y: usize) -> bool { let x = self.root(x); let y = self.root(y); if x != y { let (x, y) = if self.data[x] <= self.data[y] { (x, y) } else { (y, x) }; self.data[x] += self.data[y]; self.data[y] = x as i32; } x != y } /// Returns `true` only if `x` and `y` are in a same set. pub fn same(&mut self, x: usize, y: usize) -> bool { self.root(x) == self.root(y) } /// Returns the number of elements of a set including `x`. pub fn size(&mut self, x: usize) -> u32 { let r = self.root(x); (-self.data[r]) as u32 } /// internal method to return representative element of a set including `x`. pub fn root(&mut self, x: usize) -> usize { if self.data[x] < 0 { x } else { let nx = self.data[x] as usize; let r = self.root(nx); self.data[x] = r as i32; r } } } fn construct_tree (cur: usize, p: usize, graph: &Vec>, count: &[usize], node: &mut Vec>) -> usize{ let mut val = vec![]; let mut ret = count[cur]; for g in &graph[cur] { if *g==p {continue;} let sum = construct_tree(*g, cur, graph, count, node); val.push((*g,sum)); ret += sum; } node[cur] = val; ret } fn find_node (cur: usize, p: usize, count: &[usize], node: &Vec>, z: usize) -> usize { let mut sum = count[cur]; for x in &node[cur] { sum += x.1; } let mut score = 0; let mut target = cur; let mut t2 = 0; for x in &node[cur] { // println!("cur {} v {} val {} sum {}", cur, x.0, x.1, sum); let v = x.0; let val = x.1; if v==p {continue;} let tmp = val as i64 - (sum as i64 - val as i64) - z as i64; // println!("{}", tmp); if tmp > score { score = tmp; target = v; t2 = val; } } // println!("target {} cur {}", target); if target==cur { return cur; } find_node(target, cur, count, node, sum-t2) // return 0; } fn solve() { let (n,m,q) = read!(usize, usize, usize); let edge = read!([usize];m); let query = read!([usize];q); let mut uf = UnionFind::new(n); let mut graph = vec![vec![];n]; for e in &edge { let s = e[0]-1; let t = e[1]-1; graph[s].push(t); graph[t].push(s); uf.unite(s,t); } let mut num = 0; let mut seen = vec![false; n]; let mut rv = vec![]; let mut id = vec![0; n]; for i in 0..n { let root = uf.root(i); if !seen[root] { num+=1; rv.push((root,num-1)); id[root] = num-1; } seen[root] = true; } let mut lca = vec![]; for i in &rv { lca.push(LCA::new(uf.size(i.0) as usize)); } let mut idx = vec![0; n]; let mut tx = vec![0;n]; for i in 0..n { let root = uf.root(i); tx[i] = idx[root]; idx[root] += 1; } for e in &edge { let s = e[0]-1; let t = e[1]-1; let root = uf.root(s); lca[id[root]].add_edge(tx[s],tx[t],1); } for i in 0..num { lca[i].init(); } let mut ans = 0; let mut count = vec![0; n]; for i in 0..q { let s = query[i][0]-1; let t = query[i][1]-1; if uf.same(s,t) { let root = uf.root(s); let z = lca[id[root]].lca(tx[s],tx[t]); let dist = lca[id[root]].euler.weight[tx[s]] + lca[id[root]].euler.weight[tx[t]] - 2*lca[id[root]].euler.weight[z]; ans += dist; } else{ count[s] += 1; count[t] += 1; } } let mut node = vec![vec![];n]; let mut tar = vec![0;n]; for i in &rv { let root = i.0; construct_tree(root, n, &graph, &count, &mut node); let target = find_node(root, n, &count, &node, 0); tar[root] = target; // println!("{}", target); } for i in 0..n { let root = uf.root(i); let z = lca[id[root]].lca(tx[i],tx[tar[root]]); let dist = lca[id[root]].euler.weight[tx[i]] + lca[id[root]].euler.weight[tx[tar[root]]] - 2*lca[id[root]].euler.weight[z]; ans += dist * count[i] as i64; // println!("i {} root {} count {} dist {}", i, root, count[i], dist); } println!("{}", ans); } fn run() { solve(); }