use std::collections::*; use std::io::Write; type Map = BTreeMap; type Set = BTreeSet; type Deque = VecDeque; fn run() { input! { n: usize, s: bytes, e: [(usize1, usize1, i64); n - 1], q: usize, ask: [(usize1, i64); q], } let mut s = s; let mut cnt = [0; 2]; for s in s.iter_mut() { if *s == b'G' { *s = 0; } else { *s = 1; } cnt[*s as usize] += 1; } let out = std::io::stdout(); let mut out = std::io::BufWriter::new(out.lock()); if cnt[0].max(cnt[1]) == n { for _ in 0..q { writeln!(out, "0").ok(); } return; } let mut g = vec![vec![]; n]; let mut hld = HLD::new(n); for &(a, b, c) in e.iter() { g[a].push(b); g[b].push(a); hld.add_edge(a, b); } let topo = |src: usize| -> Vec<(usize, usize)> { let mut res = vec![(0, n)]; for i in 0..n { let (v, p) = res[i]; for &u in g[v].iter() { if u != p { res.push((u, v)); } } } res }; let ord = topo(0); let mut root = 0; let mut size = vec![1; n]; for &(v, p) in ord.iter().rev() { let mut max = 0usize; for &u in g[v].iter() { if u != p { max = max.max(size[u]); size[v] += size[u]; } } max = max.max(n - size[v]); if 2 * max <= n { root = v; break; } } hld.build(root); let mut dp = s .iter() .map(|s| { let mut cnt = [0; 2]; cnt[*s as usize] += 1; cnt }) .collect::>(); for i in (0..n).rev() { let v = hld.vertex(i); let mut val = dp[v]; for &u in hld.child[v].iter() { val[0] += dp[u][0]; val[1] += dp[u][1]; } dp[v] = val; } if cnt[0] > cnt[1] { for dp in dp.iter_mut() { *dp = [dp[1], dp[0]]; } cnt = [cnt[1], cnt[0]]; } let mut pos = vec![]; for i in 0..n { let v = hld.vertex(i); let (l, r) = hld.sub_tree(v); if r - l == cnt[0] { pos.push(i); } } let mut seg = std::cell::RefCell::new(LazySegmentTree::build( (0..pos.len()).map(|_| 0), pos.len(), R, )); let update = |k: usize, w: i64| { let (a, b, _) = e[k]; let (p, c) = if hld.parent[a] == b { (b, a) } else { (a, b) }; let (l, r) = hld.sub_tree(c); let mut x = pos.lower_bound(&l); let mut y = pos.lower_bound(&r); let sub = dp[c]; let mut seg = seg.borrow_mut(); if x > 0 && hld.sub_tree(hld.vertex(pos[x - 1])).1 >= r { seg.update(x - 1, x, w * sub[1] as i64); x -= 1; } else { let need = cnt[0] - sub[0]; seg.update(x, y, w * need as i64); } seg.update(0, x, w * sub[0] as i64); seg.update(y, pos.len(), w * sub[0] as i64); }; for i in 0..(n - 1) { let (a, b, w) = e[i]; update(i, w); // writeln!(out, "{}", seg.borrow_mut().find(0, pos.len())).ok(); } for (k, w) in ask { update(k, w); writeln!(out, "{}", seg.borrow_mut().find(0, pos.len())).ok(); } } struct R; impl TE for R { type T = i64; type E = i64; fn fold(&self, l: &Self::T, r: &Self::T) -> Self::T { std::cmp::min(*l, *r) } fn eval(&self, x: &Self::T, f: &Self::E) -> Self::T { *x + *f } fn merge(&self, g: &Self::E, h: &Self::E) -> Self::E { *g + *h } fn e(&self) -> Self::T { std::i64::MAX / 2 } fn id(&self) -> Self::E { 0 } } fn main() { run(); } // ---------- begin input macro ---------- // reference: https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8 #[macro_export] macro_rules! input { (source = $s:expr, $($r:tt)*) => { let mut iter = $s.split_whitespace(); input_inner!{iter, $($r)*} }; ($($r:tt)*) => { let s = { use std::io::Read; let mut s = String::new(); std::io::stdin().read_to_string(&mut s).unwrap(); s }; let mut iter = s.split_whitespace(); input_inner!{iter, $($r)*} }; } #[macro_export] macro_rules! input_inner { ($iter:expr) => {}; ($iter:expr, ) => {}; ($iter:expr, $var:ident : $t:tt $($r:tt)*) => { let $var = read_value!($iter, $t); input_inner!{$iter $($r)*} }; } #[macro_export] macro_rules! read_value { ($iter:expr, ( $($t:tt),* )) => { ( $(read_value!($iter, $t)),* ) }; ($iter:expr, [ $t:tt ; $len:expr ]) => { (0..$len).map(|_| read_value!($iter, $t)).collect::>() }; ($iter:expr, chars) => { read_value!($iter, String).chars().collect::>() }; ($iter:expr, bytes) => { read_value!($iter, String).bytes().collect::>() }; ($iter:expr, usize1) => { read_value!($iter, usize) - 1 }; ($iter:expr, $t:ty) => { $iter.next().unwrap().parse::<$t>().expect("Parse error") }; } // ---------- end input macro ---------- // ---------- begin Heavy-Light decomposition ---------- pub struct HLD { size: usize, edge: Vec<(usize, usize)>, child: Vec>, path_root: Vec, parent: Vec, left: Vec, right: Vec, inverse: Vec, } impl HLD { pub fn new(size: usize) -> Self { assert!(size <= 10usize.pow(8)); HLD { size: size, edge: Vec::with_capacity(size - 1), child: Vec::new(), path_root: Vec::new(), parent: Vec::new(), left: Vec::new(), right: Vec::new(), inverse: Vec::new(), } } pub fn add_edge(&mut self, a: usize, b: usize) { assert!(a != b && a < self.size && b < self.size); self.edge.push((a, b)); } pub fn build(&mut self, root: usize) { assert!(self.edge.len() + 1 == self.size); let size = self.size; let mut cnt = vec![0; size]; for &(a, b) in self.edge.iter() { cnt[a] += 1; cnt[b] += 1; } let mut child = cnt .into_iter() .map(|c| Vec::with_capacity(c)) .collect::>(); for &(a, b) in self.edge.iter() { child[a].push(b); child[b].push(a); } let mut parent = vec![size; size]; let mut q = Vec::with_capacity(size); q.push(root); parent[root] = root; for i in 0..size { let v = q[i]; for u in child[v].clone() { assert!(parent[u] == size); parent[u] = v; child[u].retain(|e| *e != v); q.push(u); } } let mut sum = vec![1; size]; for &v in q.iter().rev() { let child = &mut child[v]; if !child.is_empty() { let (pos, _) = child.iter().enumerate().max_by_key(|p| sum[*p.1]).unwrap(); child.swap(0, pos); sum[v] = 1 + child.iter().fold(0, |s, a| s + sum[*a]); } } let mut path_root = (0..size).collect::>(); let mut left = vec![0; size]; let mut right = vec![0; size]; let mut dfs = vec![(root, false)]; let mut id = 0; while let Some((v, end)) = dfs.pop() { if end { right[v] = id; continue; } left[v] = id; id += 1; dfs.push((v, true)); let child = &child[v]; if !child.is_empty() { for &u in child[1..].iter() { path_root[u] = u; dfs.push((u, false)); } let u = child[0]; path_root[u] = path_root[v]; dfs.push((u, false)); } } let mut inverse = vec![size; size]; for (i, l) in left.iter().enumerate() { inverse[*l] = i; } self.child = child; self.parent = parent; self.left = left; self.right = right; self.path_root = path_root; self.inverse = inverse; } pub fn lca(&self, mut a: usize, mut b: usize) -> usize { assert!(a < self.size && b < self.size); let path = &self.path_root; let parent = &self.parent; let index = &self.left; while path[a] != path[b] { if index[a] > index[b] { std::mem::swap(&mut a, &mut b); } b = parent[path[b]]; } std::cmp::min((index[a], a), (index[b], b)).1 } pub fn path( &self, src: usize, dst: usize, up: &mut Vec<(usize, usize)>, down: &mut Vec<(usize, usize)>, ) { assert!(src < self.size && dst < self.size); up.clear(); down.clear(); let path = &self.path_root; let parent = &self.parent; let index = &self.left; let mut x = src; let mut y = dst; while path[x] != path[y] { if index[x] > index[y] { let p = path[x]; assert!(p == path[p]); up.push((index[p], index[x] + 1)); x = parent[p]; } else { let p = path[y]; assert!(p == path[p]); down.push((index[p], index[y] + 1)); y = parent[p]; } } if index[x] <= index[y] { down.push((index[x], index[y] + 1)); } else { up.push((index[y], index[x] + 1)); } down.reverse(); } pub fn sub_tree(&self, v: usize) -> (usize, usize) { assert!(v < self.size); (self.left[v], self.right[v]) } pub fn parent(&self, v: usize) -> Option { assert!(v < self.size); let p = self.parent[v]; if p == v { None } else { Some(p) } } // s -> t へのパスの2番目の頂点を返す pub fn next(&self, s: usize, t: usize) -> usize { assert!(s < self.size && t < self.size && s != t); let (a, b) = self.sub_tree(s); let (c, d) = self.sub_tree(t); if !(a <= c && d <= b) { return self.parent[s]; } let mut pos = t; let mut pre = t; while self.path_root[s] != self.path_root[pos] { pre = self.path_root[pos]; pos = self.parent[pre]; } if s == pos { pre } else { self.child[s][0] } } pub fn vertex(&self, x: usize) -> usize { assert!(x < self.size); self.inverse[x] } pub fn jump( &self, s: usize, t: usize, mut k: usize, up: &mut Vec<(usize, usize)>, down: &mut Vec<(usize, usize)>, ) -> Option { assert!(s.max(t) < self.size); self.path(s, t, up, down); for (l, r) in up.drain(..) { if k < r - l { return Some(self.vertex(r - 1 - k)); } k -= r - l; } for (l, r) in down.drain(..) { if k < r - l { return Some(self.vertex(l + k)); } k -= r - l; } None } } // ---------- end Heavy-Light decomposition ---------- // ---------- begin Lazy Segment Tree ---------- pub trait TE { type T: Clone; type E: Clone; fn fold(&self, l: &Self::T, r: &Self::T) -> Self::T; fn eval(&self, x: &Self::T, f: &Self::E) -> Self::T; fn merge(&self, g: &Self::E, h: &Self::E) -> Self::E; fn e(&self) -> Self::T; fn id(&self) -> Self::E; } pub struct LazySegmentTree { n: usize, size: usize, bit: u32, op: R, data: Vec<(R::T, R::E)>, } impl LazySegmentTree { pub fn new(n: usize, op: R) -> Self { assert!(n > 0); let size = n.next_power_of_two(); let bit = size.trailing_zeros(); let data = vec![(op.e(), op.id()); 2 * size]; Self { n, size, bit, op, data, } } pub fn build(init: I, n: usize, op: R) -> Self where I: Iterator, { let mut seg = Self::new(n, op); for (data, ini) in seg.data[seg.size..].iter_mut().zip(init) { data.0 = ini; } for i in (1..seg.size).rev() { seg.pull(i); } seg } pub fn update(&mut self, l: usize, r: usize, f: R::E) { assert!(l <= r && r <= self.n); if l == r { return; } self.push_range(l, r); let mut s = l + self.size; let mut t = r + self.size; while s < t { if s & 1 == 1 { self.apply(s, &f); s += 1; } if t & 1 == 1 { t -= 1; self.apply(t, &f); } s >>= 1; t >>= 1; } let l = l + self.size; let r = r + self.size; for k in 1..=self.bit { if (l >> k) << k != l { self.pull(l >> k); } if (r >> k) << k != r { self.pull((r - 1) >> k); } } } pub fn find(&mut self, l: usize, r: usize) -> R::T { assert!(l <= r && r <= self.n); if l == r { return self.op.e(); } self.push_range(l, r); let mut l = l + self.size; let mut r = r + self.size; let mut p = self.op.e(); let mut q = self.op.e(); while l < r { if l & 1 == 1 { p = self.op.fold(&p, &self.data[l].0); l += 1; } if r & 1 == 1 { r -= 1; q = self.op.fold(&self.data[r].0, &q); } l >>= 1; r >>= 1; } self.op.fold(&p, &q) } pub fn set_at(&mut self, x: usize, v: R::T) { assert!(x < self.n); let x = x + self.size; for k in (1..=self.bit).rev() { self.push(x >> k); } self.data[x].0 = v; for k in 1..=self.bit { self.pull(x >> k); } } fn push_range(&mut self, l: usize, r: usize) { let l = l + self.size; let r = r + self.size; for k in (1..=self.bit).rev() { if (l >> k) << k != l { self.push(l >> k); } if (r >> k) << k != r { self.push((r - 1) >> k); } } } fn apply(&mut self, x: usize, f: &R::E) { self.data[x].0 = self.op.eval(&self.data[x].0, f); self.data[x].1 = self.op.merge(&self.data[x].1, f); } fn push(&mut self, x: usize) { let f = std::mem::replace(&mut self.data[x].1, self.op.id()); self.apply(2 * x, &f); self.apply(2 * x + 1, &f); } fn pull(&mut self, x: usize) { self.data[x].0 = self.op.fold(&self.data[2 * x].0, &self.data[2 * x + 1].0); } } // ---------- end Lazy Segment Tree ---------- // ---------- begin super slice ---------- pub trait SuperSlice { type Item; fn lower_bound(&self, key: &Self::Item) -> usize where Self::Item: Ord; fn lower_bound_by(&self, f: F) -> usize where F: FnMut(&Self::Item) -> std::cmp::Ordering; fn lower_bound_by_key(&self, key: &K, f: F) -> usize where K: Ord, F: FnMut(&Self::Item) -> K; fn upper_bound(&self, key: &Self::Item) -> usize where Self::Item: Ord; fn upper_bound_by(&self, f: F) -> usize where F: FnMut(&Self::Item) -> std::cmp::Ordering; fn upper_bound_by_key(&self, key: &K, f: F) -> usize where K: Ord, F: FnMut(&Self::Item) -> K; fn next_permutation(&mut self) -> bool where Self::Item: Ord; fn next_permutation_by(&mut self, f: F) -> bool where F: FnMut(&Self::Item, &Self::Item) -> std::cmp::Ordering; fn prev_permutation(&mut self) -> bool where Self::Item: Ord; } impl SuperSlice for [T] { type Item = T; fn lower_bound(&self, key: &Self::Item) -> usize where T: Ord, { self.lower_bound_by(|p| p.cmp(key)) } fn lower_bound_by(&self, mut f: F) -> usize where F: FnMut(&Self::Item) -> std::cmp::Ordering, { self.binary_search_by(|p| f(p).then(std::cmp::Ordering::Greater)) .unwrap_err() } fn lower_bound_by_key(&self, key: &K, mut f: F) -> usize where K: Ord, F: FnMut(&Self::Item) -> K, { self.lower_bound_by(|p| f(p).cmp(key)) } fn upper_bound(&self, key: &Self::Item) -> usize where T: Ord, { self.upper_bound_by(|p| p.cmp(key)) } fn upper_bound_by(&self, mut f: F) -> usize where F: FnMut(&Self::Item) -> std::cmp::Ordering, { self.binary_search_by(|p| f(p).then(std::cmp::Ordering::Less)) .unwrap_err() } fn upper_bound_by_key(&self, key: &K, mut f: F) -> usize where K: Ord, F: FnMut(&Self::Item) -> K, { self.upper_bound_by(|p| f(p).cmp(key)) } fn next_permutation(&mut self) -> bool where T: Ord, { self.next_permutation_by(|a, b| a.cmp(b)) } fn next_permutation_by(&mut self, mut f: F) -> bool where F: FnMut(&Self::Item, &Self::Item) -> std::cmp::Ordering, { use std::cmp::Ordering::*; if let Some(x) = self.windows(2).rposition(|a| f(&a[0], &a[1]) == Less) { let y = self.iter().rposition(|b| f(&self[x], b) == Less).unwrap(); self.swap(x, y); self[(x + 1)..].reverse(); true } else { self.reverse(); false } } fn prev_permutation(&mut self) -> bool where T: Ord, { self.next_permutation_by(|a, b| a.cmp(b).reverse()) } } // ---------- end super slice ----------