package main
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
)
type Bucket struct {
idxs []int
}
type Frame struct {
name string
adv []int
}
func main() {
data, _ := io.ReadAll(os.Stdin)
text := string(data)
text = strings.ReplaceAll(text, "\r", "")
lines := strings.Split(strings.TrimRight(text, "\n"), "\n")
if len(lines) < 2 {
return
}
doc := lines[0]
m, _ := strconv.Atoi(strings.TrimSpace(lines[1]))
queries := make([][]string, m)
for i := 0; i < m; i++ {
if 2+i < len(lines) {
queries[i] = strings.Fields(strings.TrimSpace(lines[2+i]))
} else {
queries[i] = []string{}
}
}
// Prepare buckets for all query tokens
buckets := make(map[string]*Bucket)
for _, q := range queries {
for _, w := range q {
if _, ok := buckets[w]; !ok {
buckets[w] = &Bucket{}
}
}
}
lens := make([]int, m)
for i := 0; i < m; i++ {
lens[i] = len(queries[i])
}
ans := make([]int, m)
k := make([]int, m) // matched prefix length
pos := make([]int, m) // position in current bucket
curKey := make([]string, m) // current bucket key for query
for i := 0; i < m; i++ {
pos[i] = -1
if lens[i] > 0 {
key := queries[i][0]
b := buckets[key]
b.idxs = append(b.idxs, i)
pos[i] = len(b.idxs) - 1
curKey[i] = key
}
}
var stack []Frame
var pop func()
// Helper: push a node
push := func(name string, selfClosing bool) {
var advancers []int
if b, ok := buckets[name]; ok {
if len(b.idxs) > 0 {
advancers = b.idxs
b.idxs = nil // detach to avoid aliasing
}
}
// Detach all from their old bucket (they are advancing now)
for _, j := range advancers {
pos[j] = -1
curKey[j] = ""
}
// Advance all
for _, j := range advancers {
k[j]++
if k[j] == lens[j] {
ans[j]++
} else {
next := queries[j][k[j]]
nb := buckets[next]
nb.idxs = append(nb.idxs, j)
pos[j] = len(nb.idxs) - 1
curKey[j] = next
}
}
stack = append(stack, Frame{name: name, adv: advancers})
if selfClosing {
// immediate pop
pop()
}
}
// Helper: pop a node
pop = func() {
if len(stack) == 0 {
return
}
fr := stack[len(stack)-1]
stack = stack[:len(stack)-1]
for _, j := range fr.adv {
// Remove from current bucket if present
if k[j] < lens[j] {
currKey := queries[j][k[j]]
b := buckets[currKey]
p := pos[j]
if p >= 0 {
last := b.idxs[len(b.idxs)-1]
b.idxs[p] = last
pos[last] = p
b.idxs = b.idxs[:len(b.idxs)-1]
}
pos[j] = -1
curKey[j] = ""
}
// Revert advancement at this frame
k[j]--
prevNext := queries[j][k[j]]
b2 := buckets[prevNext]
b2.idxs = append(b2.idxs, j)
pos[j] = len(b2.idxs) - 1
curKey[j] = prevNext
}
}
// Parse document
n := len(doc)
for i := 0; i < n; {
if doc[i] != '<' {
i++
continue
}
i++ // skip '<'
if i < n && doc[i] == '/' {
// closing
i++
for i < n && doc[i] != '>' {
i++
}
if i < n && doc[i] == '>' {
i++
}
pop()
} else {
// opening or self-closing
start := i
for i < n {
c := doc[i]
if c == '/' || c == '>' {
break
}
i++
}
name := doc[start:i]
if i < n && doc[i] == '/' {
// self-closing
i++
if i < n && doc[i] == '>' {
i++
}
push(name, true)
} else {
// opening
if i < n && doc[i] == '>' {
i++
}
push(name, false)
}
}
}
w := bufio.NewWriter(os.Stdout)
for i := 0; i < m; i++ {
fmt.Fprintln(w, ans[i])
}
w.Flush()
}