package main
import (
"bufio"
"fmt"
"os"
)
type SegTree struct {
tree []int
lazy []int
}
func newSegTree(n int) SegTree {
return SegTree{
tree: make([]int, 4*n),
lazy: make([]int, 4*n),
}
}
func (st *SegTree) push(node int) {
if st.lazy[node] != 0 {
st.tree[2*node] += st.lazy[node]
st.lazy[2*node] += st.lazy[node]
st.tree[2*node+1] += st.lazy[node]
st.lazy[2*node+1] += st.lazy[node]
st.lazy[node] = 0
}
}
func (st *SegTree) add(node, l, r, ql, qr, val int) {
if ql > r || qr < l {
return
}
if ql <= l && r <= qr {
st.tree[node] += val
st.lazy[node] += val
return
}
st.push(node)
mid := l + (r-l)/2
st.add(2*node, l, mid, ql, qr, val)
st.add(2*node+1, mid+1, r, ql, qr, val)
if st.tree[2*node] > st.tree[2*node+1] {
st.tree[node] = st.tree[2*node]
} else {
st.tree[node] = st.tree[2*node+1]
}
}
func (st *SegTree) query(node, l, r, ql, qr int) int {
if ql > r || qr < l {
return -1e9
}
if ql <= l && r <= qr {
return st.tree[node]
}
st.push(node)
mid := l + (r-l)/2
left := st.query(2*node, l, mid, ql, qr)
right := st.query(2*node+1, mid+1, r, ql, qr)
if left > right {
return left
}
return right
}
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
scanner.Buffer(make([]byte, 1024*1024*10), 1024*1024*10)
scanString := func() string {
scanner.Scan()
return scanner.Text()
}
scanInt := func() int {
scanner.Scan()
res := 0
s := scanner.Text()
for _, c := range s {
res = res*10 + int(c-'0')
}
return res
}
n := scanInt()
q := scanInt()
parent := make([]int, n+1)
adj := make([][]int, n+1)
initialChar := make([]byte, n+1)
edgeChar := make([]byte, n+1)
for i := 1; i <= n-1; i++ {
p := scanInt()
cStr := scanString()
u := i + 1
parent[u] = p
adj[p] = append(adj[p], u)
initialChar[u] = cStr[0]
edgeChar[u] = '?'
}
sz := make([]int, n+1)
depth := make([]int, n+1)
heavyChild := make([]int, n+1)
var dfsSz func(int)
dfsSz = func(u int) {
sz[u] = 1
maxSub := 0
for _, v := range adj[u] {
depth[v] = depth[u] + 1
dfsSz(v)
sz[u] += sz[v]
if sz[v] > maxSub {
maxSub = sz[v]
heavyChild[u] = v
}
}
}
dfsSz(1)
hldHead := make([]int, n+1)
hldPos := make([]int, n+1)
hldNode := make([]int, n+1)
hldPosIn := make([]int, n+1)
hldPosOut := make([]int, n+1)
hldTimer := 0
var dfsHld func(int, int)
dfsHld = func(u, h int) {
hldHead[u] = h
hldTimer++
hldPos[u] = hldTimer
hldNode[hldTimer] = u
hldPosIn[u] = hldTimer
if heavyChild[u] != 0 {
dfsHld(heavyChild[u], h)
}
for _, v := range adj[u] {
if v != heavyChild[u] {
dfsHld(v, v)
}
}
hldPosOut[u] = hldTimer
}
dfsHld(1, 1)
leafIn := make([]int, n+1)
leafOut := make([]int, n+1)
leafTimer := 0
possible := true
D := -1
var dfsLeaves func(int)
dfsLeaves = func(u int) {
isLeaf := true
leafIn[u] = leafTimer
for _, v := range adj[u] {
isLeaf = false
dfsLeaves(v)
}
if isLeaf {
if D == -1 {
D = depth[u]
} else if D != depth[u] {
possible = false
}
leafTimer++
}
leafOut[u] = leafTimer - 1
}
dfsLeaves(1)
numLeaves := leafTimer
var leafST [26]SegTree
for i := 0; i < 26; i++ {
leafST[i] = newSegTree(numLeaves)
}
globalST := newSegTree(n)
for i := 1; i <= n; i++ {
v := hldNode[i]
globalST.add(1, 1, n, i, i, depth[v]-D)
}
updateEdge := func(u int, newC byte) {
oldC := edgeChar[u]
if oldC == newC {
return
}
if oldC == '?' {
globalST.add(1, 1, n, hldPosIn[u], hldPosOut[u], -1)
} else {
c := int(oldC - 'a')
leafST[c].add(1, 0, numLeaves-1, leafIn[u], leafOut[u], -1)
target := leafST[c].query(1, 0, numLeaves-1, leafIn[u], leafOut[u])
topNode := u
curr := parent[u]
for curr > 0 {
if leafST[c].query(1, 0, numLeaves-1, leafIn[curr], leafOut[curr]) != target {
break
}
head := hldHead[curr]
if leafST[c].query(1, 0, numLeaves-1, leafIn[head], leafOut[head]) == target {
topNode = head
curr = parent[head]
} else {
low := hldPos[head]
high := hldPos[curr]
ansPos := high
for low <= high {
mid := low + (high-low)/2
node := hldNode[mid]
if leafST[c].query(1, 0, numLeaves-1, leafIn[node], leafOut[node]) == target {
ansPos = mid
high = mid - 1
} else {
low = mid + 1
}
}
topNode = hldNode[ansPos]
break
}
}
globalST.add(1, 1, n, hldPosIn[u], hldPosOut[u], -1)
if topNode != u {
curr = parent[u]
for depth[curr] >= depth[topNode] {
head := hldHead[curr]
if depth[head] < depth[topNode] {
head = topNode
}
globalST.add(1, 1, n, hldPos[head], hldPos[curr], -1)
curr = parent[head]
if curr == 0 {
break
}
}
}
}
if newC == '?' {
globalST.add(1, 1, n, hldPosIn[u], hldPosOut[u], 1)
} else {
c := int(newC - 'a')
target := leafST[c].query(1, 0, numLeaves-1, leafIn[u], leafOut[u])
topNode := u
curr := parent[u]
for curr > 0 {
if leafST[c].query(1, 0, numLeaves-1, leafIn[curr], leafOut[curr]) != target {
break
}
head := hldHead[curr]
if leafST[c].query(1, 0, numLeaves-1, leafIn[head], leafOut[head]) == target {
topNode = head
curr = parent[head]
} else {
low := hldPos[head]
high := hldPos[curr]
ansPos := high
for low <= high {
mid := low + (high-low)/2
node := hldNode[mid]
if leafST[c].query(1, 0, numLeaves-1, leafIn[node], leafOut[node]) == target {
ansPos = mid
high = mid - 1
} else {
low = mid + 1
}
}
topNode = hldNode[ansPos]
break
}
}
leafST[c].add(1, 0, numLeaves-1, leafIn[u], leafOut[u], 1)
globalST.add(1, 1, n, hldPosIn[u], hldPosOut[u], 1)
if topNode != u {
curr = parent[u]
for depth[curr] >= depth[topNode] {
head := hldHead[curr]
if depth[head] < depth[topNode] {
head = topNode
}
globalST.add(1, 1, n, hldPos[head], hldPos[curr], 1)
curr = parent[head]
if curr == 0 {
break
}
}
}
}
edgeChar[u] = newC
}
for i := 2; i <= n; i++ {
if initialChar[i] != '?' {
updateEdge(i, initialChar[i])
}
}
for i := 0; i < q; i++ {
v := scanInt()
cStr := scanString()
c := cStr[0]
updateEdge(v, c)
if !possible {
fmt.Println("Fou")
} else if globalST.query(1, 1, n, 1, n) > 0 {
fmt.Println("Fou")
} else {
S := 0
var maxC [26]int
for j := 0; j < 26; j++ {
maxC[j] = leafST[j].query(1, 0, numLeaves-1, 0, numLeaves-1)
S += maxC[j]
}
ans := 0
for j := 0; j < 26; j++ {
f := maxC[j] + D - S
ans += f * (j + 1)
}
fmt.Printf("Shi %d\n", ans)
}
}
}