import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class CF1168D {
    public static void main(String[] args) throws Exception {
        boolean local = System.getProperty("ONLINE_JUDGE") == null;
        boolean async = false;

        Charset charset = Charset.forName("ascii");

        FastIO io = local ? new FastIO(new FileInputStream("D:\\DATABASE\\TESTCASE\\Code.in"), System.out, charset) : new FastIO(System.in, System.out, charset);
        Task task = new Task(io, new Debug(local));

        if (async) {
            Thread t = new Thread(null, task, "dalt", 1 << 27);
            t.setPriority(Thread.MAX_PRIORITY);
            t.start();
            t.join();
        } else {
            task.run();
        }

        if (local) {
            io.cache.append("\n\n--memory -- \n" + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) >> 20) + "M");
        }

        io.flush();
    }

    public static class Task implements Runnable {
        final FastIO io;
        final Debug debug;
        int inf = (int) 1e8;

        public Task(FastIO io, Debug debug) {
            this.io = io;
            this.debug = debug;
        }

        @Override
        public void run() {
            solve();
        }

        Node[] nodes;

        public void solve() {
            int n = io.readInt();
            int q = io.readInt();
            nodes = new Node[n + 1];
            for (int i = 1; i <= n; i++) {
                nodes[i] = new Node();
                nodes[i].id = i;
            }
            int[] color = new int[n + 1];
            for (int i = 2; i <= n; i++) {
                setFather(nodes[i], nodes[io.readInt()]);
                color[i] = io.readChar();
                if (color[i] != '?') {
                    nodes[i].edges[color[i] - 'a']++;
                }
            }
            dfs(nodes[1], 1);
            compress(nodes[1], null);
            dpOnTree(nodes[1]);

            for (int i = 0; i < q; i++) {
                Node v = nodes[io.readInt()];
                int c = io.readChar();
                int old = color[v.id];
                color[v.id] = c;
                if (old != '?') {
                    v.edges[old - 'a']--;
                }
                if (c != '?') {
                    v.edges[c - 'a']++;
                }
                shiftUp(v);

                if (invalidCount > 0) {
                    io.cache.append("Fou\n");
                    continue;
                }

                int sum = 0;
                for (int j = 0; j < Node.SIZE; j++) {
                    sum += nodes[1].dp[j];
                }
                int flexible = leafDepth - 1 - sum;
                int func = 0;
                for (int j = 0; j < Node.SIZE; j++) {
                    func += (j + 1) * (flexible + nodes[1].dp[j]);
                }

                io.cache.append("Shi ").append(func).append('\n');
            }
        }

        public void dpOnNode(Node root, Node child) {
            for (int i = 0; i < Node.SIZE; i++) {
                root.dp[i] = Math.max(root.dp[i], root.edges[i] + child.dp[i]);
            }
        }

        public void shiftUp(Node root) {
            while (root != null) {
                dpOnNode(root);
                root = root.father;
            }
        }

        public void dpOnNode(Node root) {
            for (int i = 0; i < Node.SIZE; i++) {
                root.dp[i] = root.edges[i];
            }
            if (root.left != null) {
                dpOnNode(root, root.left);
            }
            if (root.right != null) {
                dpOnNode(root, root.right);
            }

            int sum = 0;
            for (int i = 0; i < Node.SIZE; i++) {
                sum += root.dp[i];
            }
            boolean valid = sum <= Math.min(leafDepth - root.depth + 1, leafDepth - 1);
            if (valid != root.valid) {
                if (valid) {
                    invalidCount--;
                } else {
                    invalidCount++;
                }
                root.valid = valid;
            }
        }

        public void dfs(Node root, int depth) {
            if (root == null) {
                return;
            }
            root.depth = depth;
            dfs(root.left, depth + 1);
            dfs(root.right, depth + 1);
            if (root.left == null && root.right == null) {
                if (leafDepth == -1) {
                    leafDepth = depth;
                }
                if (leafDepth != depth) {
                    invalidCount = inf;
                }
            }
        }

        int leafDepth = -1;
        int invalidCount = 0;

        public void dpOnTree(Node root) {
            if (root == null) {
                return;
            }
            dpOnTree(root.left);
            dpOnTree(root.right);
            dpOnNode(root);
        }

        public void compress(Node root, Node father) {
            if (root == null) {
                return;
            }
            root.father = father;
            while (root.left != null && root.right == null) {
                for (int i = 0; i < Node.SIZE; i++) {
                    root.edges[i] += root.left.edges[i];
                }
                nodes[root.left.id] = root;
                root.right = root.left.right;
                root.left = root.left.left;
            }
            compress(root.left, root);
            compress(root.right, root);
        }

        public void setFather(Node node, Node father) {
            node.father = father;
            if (father.left == null) {
                father.left = node;
            } else if (father.right == null) {
                father.right = node;
            }
        }
    }

    public static class Node {
        public static final int SIZE = 'z' - 'a' + 1;
        int[] dp = new int[SIZE];
        int[] edges = new int[SIZE];
        Node left;
        Node right;
        int depth;
        int id;
        Node father;
        boolean valid = true;
    }

    public static class FastIO {
        public final StringBuilder cache = new StringBuilder();
        private final InputStream is;
        private final OutputStream os;
        private final Charset charset;
        private StringBuilder defaultStringBuf = new StringBuilder(1 << 8);
        private byte[] buf = new byte[1 << 13];
        private int bufLen;
        private int bufOffset;
        private int next;

        public FastIO(InputStream is, OutputStream os, Charset charset) {
            this.is = is;
            this.os = os;
            this.charset = charset;
        }

        public FastIO(InputStream is, OutputStream os) {
            this(is, os, Charset.forName("ascii"));
        }

        private int read() {
            while (bufLen == bufOffset) {
                bufOffset = 0;
                try {
                    bufLen = is.read(buf);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                if (bufLen == -1) {
                    return -1;
                }
            }
            return buf[bufOffset++];
        }

        public void skipBlank() {
            while (next >= 0 && next <= 32) {
                next = read();
            }
        }

        public int readInt() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            int val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

        public long readLong() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            long val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

        public double readDouble() {
            boolean sign = true;
            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+';
                next = read();
            }

            long val = 0;
            while (next >= '0' && next <= '9') {
                val = val * 10 + next - '0';
                next = read();
            }
            if (next != '.') {
                return sign ? val : -val;
            }
            next = read();
            long radix = 1;
            long point = 0;
            while (next >= '0' && next <= '9') {
                point = point * 10 + next - '0';
                radix = radix * 10;
                next = read();
            }
            double result = val + (double) point / radix;
            return sign ? result : -result;
        }

        public String readString(StringBuilder builder) {
            skipBlank();

            while (next > 32) {
                builder.append((char) next);
                next = read();
            }

            return builder.toString();
        }

        public String readString() {
            defaultStringBuf.setLength(0);
            return readString(defaultStringBuf);
        }

        public int readLine(char[] data, int offset) {
            int originalOffset = offset;
            while (next != -1 && next != '\n') {
                data[offset++] = (char) next;
                next = read();
            }
            return offset - originalOffset;
        }

        public int readString(char[] data, int offset) {
            skipBlank();

            int originalOffset = offset;
            while (next > 32) {
                data[offset++] = (char) next;
                next = read();
            }

            return offset - originalOffset;
        }

        public int readString(byte[] data, int offset) {
            skipBlank();

            int originalOffset = offset;
            while (next > 32) {
                data[offset++] = (byte) next;
                next = read();
            }

            return offset - originalOffset;
        }

        public char readChar() {
            skipBlank();
            char c = (char) next;
            next = read();
            return c;
        }

        public void flush() {
            try {
                os.write(cache.toString().getBytes(charset));
                os.flush();
                cache.setLength(0);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        public boolean hasMore() {
            skipBlank();
            return next != -1;
        }
    }

    public static class Debug {
        private boolean allowDebug;

        public Debug(boolean allowDebug) {
            this.allowDebug = allowDebug;
        }

        public void assertTrue(boolean flag) {
            if (!allowDebug) {
                return;
            }
            if (!flag) {
                fail();
            }
        }

        public void fail() {
            throw new RuntimeException();
        }

        public void assertFalse(boolean flag) {
            if (!allowDebug) {
                return;
            }
            if (flag) {
                fail();
            }
        }

        private void outputName(String name) {
            System.out.print(name + " = ");
        }

        public void debug(String name, int x) {
            if (!allowDebug) {
                return;
            }

            outputName(name);
            System.out.println("" + x);
        }

        public void debug(String name, long x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println("" + x);
        }

        public void debug(String name, double x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println("" + x);
        }

        public void debug(String name, int[] x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println(Arrays.toString(x));
        }

        public void debug(String name, long[] x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println(Arrays.toString(x));
        }

        public void debug(String name, double[] x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println(Arrays.toString(x));
        }

        public void debug(String name, Object x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println("" + x);
        }

        public void debug(String name, Object... x) {
            if (!allowDebug) {
                return;
            }
            outputName(name);
            System.out.println(Arrays.deepToString(x));
        }
    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskD solver = new TaskD();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskD {
        int WILDCARD = 26;
        int numInvalid;
        int leafDepth;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            int n = in.nextInt();
            int q = in.nextInt();
            TaskD.Vertex[] vs = new TaskD.Vertex[n];
            vs[0] = new TaskD.Vertex();
            vs[0].parentChar = -1;
            for (int i = 1; i < n; ++i) {
                vs[i] = new TaskD.Vertex();
                vs[i].parent = vs[in.nextInt() - 1];
                ++vs[i].parent.numChildren;
                vs[i].depth = 1 + vs[i].parent.depth;
                char ch = in.next().charAt(0);
                if (ch == '?') {
                    vs[i].parentChar = WILDCARD;
                } else {
                    vs[i].parentChar = ch - 'a';
                }
            }
            leafDepth = -1;
            for (TaskD.Vertex v : vs)
                if (v.numChildren == 0) {
                    if (leafDepth < 0) leafDepth = v.depth;
                    if (leafDepth != v.depth) {
                        for (int i = 0; i < q; ++i) {
                            out.println("Fou");
                        }
                        return;
                    }
                }
            if (leafDepth < 0) throw new RuntimeException();
            TaskD.Vertex[] interesting = new TaskD.Vertex[n];
            int interestingCount = 0;
            for (TaskD.Vertex v : vs) {
                if (v.parent == null || v.numChildren != 1) {
                    interesting[interestingCount++] = v;
                }
            }
            interesting = Arrays.copyOf(interesting, interestingCount);
            reverseArray(interesting);
            for (TaskD.Vertex v : interesting) {
                v.quickCount = new int[27];
                v.subtreeCount = new int[27];
            }
            numInvalid = 0;
            for (TaskD.Vertex v : interesting) {
                v.subtreeSum = 0;
                for (int i = 0; i < 26; ++i) v.subtreeSum += v.subtreeCount[i];
                if (v.subtreeSum > leafDepth - v.depth) {
                    ++numInvalid;
                }
                if (v.parent != null) {
                    v.quickChild = v;
                    ++v.quickCount[v.parentChar];
                    TaskD.Vertex u = v.parent;
                    while (u.parent != null && u.numChildren == 1) {
                        ++v.quickCount[u.parentChar];
                        u.quickChild = v;
                        u = u.parent;
                    }
                    v.quickParent = u;
                    for (int i = 0; i < 26; ++i) {
                        u.subtreeCount[i] = Math.max(u.subtreeCount[i], v.subtreeCount[i] + v.quickCount[i]);
                    }
                    v.nextSibling = u.firstChild;
                    u.firstChild = v;
                }
            }
            for (int qi = 0; qi < q; ++qi) {
                TaskD.Vertex u = vs[in.nextInt() - 1];
                TaskD.Vertex v = u.quickChild;
                int c1 = u.parentChar;
                char ch = in.next().charAt(0);
                int c2;
                if (ch == '?') {
                    c2 = WILDCARD;
                } else {
                    c2 = ch - 'a';
                }
                if (c1 != c2) {
                    u.parentChar = c2;
                    if (c1 < 26) {
                        --v.quickCount[c1];
                        propagate(v, c1);
                    }
                    if (c2 < 26) {
                        ++v.quickCount[c2];
                        propagate(v, c2);
                    }
                }
                if (numInvalid == 0) {
                    int s = 0;
                    int spare = leafDepth - vs[0].subtreeSum;
                    for (int i = 0; i < 26; ++i) {
                        s += (i + 1) * (vs[0].subtreeCount[i] + spare);
                    }
                    out.println("Shi " + s);
                } else {
                    out.println("Fou");
                }
            }
        }

        private void propagate(TaskD.Vertex v, int what) {
            TaskD.Vertex u = v.quickParent;
            if (u.subtreeSum > leafDepth - u.depth) {
                --numInvalid;
            }
            int old = u.subtreeCount[what];
            u.subtreeSum -= old;
            u.subtreeCount[what] = 0;
            for (TaskD.Vertex t = u.firstChild; t != null; t = t.nextSibling) {
                u.subtreeCount[what] = Math.max(u.subtreeCount[what], t.subtreeCount[what] + t.quickCount[what]);
            }
            u.subtreeSum += u.subtreeCount[what];
            if (u.subtreeSum > leafDepth - u.depth) {
                ++numInvalid;
            }
            if (u.parent != null && u.subtreeCount[what] != old) {
                propagate(u, what);
            }
        }

        private void reverseArray(TaskD.Vertex[] a) {
            for (int i = 0, j = a.length - 1; i < j; ++i, --j) {
                TaskD.Vertex t = a[i];
                a[i] = a[j];
                a[j] = t;
            }
        }

        static class Vertex {
            TaskD.Vertex parent;
            int parentChar;
            int depth;
            int numChildren;
            TaskD.Vertex quickParent;
            TaskD.Vertex quickChild;
            int[] quickCount;
            int[] subtreeCount;
            TaskD.Vertex firstChild;
            TaskD.Vertex nextSibling;
            int subtreeSum;

        }

    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskD solver = new TaskD();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskD {
        int WILDCARD = 26;
        int numInvalid;
        int leafDepth;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            int n = in.nextInt();
            int q = in.nextInt();
            TaskD.Vertex[] vs = new TaskD.Vertex[n];
            vs[0] = new TaskD.Vertex();
            vs[0].parentChar = -1;
            for (int i = 1; i < n; ++i) {
                vs[i] = new TaskD.Vertex();
                vs[i].parent = vs[in.nextInt() - 1];
                ++vs[i].parent.numChildren;
                vs[i].depth = 1 + vs[i].parent.depth;
                char ch = in.next().charAt(0);
                if (ch == '?') {
                    vs[i].parentChar = WILDCARD;
                } else {
                    vs[i].parentChar = ch - 'a';
                }
            }
            leafDepth = -1;
            for (TaskD.Vertex v : vs)
                if (v.numChildren == 0) {
                    if (leafDepth < 0) leafDepth = v.depth;
                    if (leafDepth != v.depth) {
                        for (int i = 0; i < q; ++i) {
                            out.println("Fou");
                        }
                        return;
                    }
                }
            if (leafDepth < 0) throw new RuntimeException();
            TaskD.Vertex[] interesting = new TaskD.Vertex[n];
            int interestingCount = 0;
            for (TaskD.Vertex v : vs) {
                if (v.parent == null || v.numChildren != 1) {
                    interesting[interestingCount++] = v;
                }
            }
            interesting = Arrays.copyOf(interesting, interestingCount);
            reverseArray(interesting);
            for (TaskD.Vertex v : interesting) {
                v.quickCount = new int[27];
                v.subtreeCount = new int[27];
            }
            numInvalid = 0;
            for (TaskD.Vertex v : interesting) {
                v.subtreeSum = 0;
                for (int i = 0; i < 26; ++i) v.subtreeSum += v.subtreeCount[i];
                if (v.subtreeSum > leafDepth - v.depth) {
                    ++numInvalid;
                }
                if (v.parent != null) {
                    v.quickChild = v;
                    ++v.quickCount[v.parentChar];
                    TaskD.Vertex u = v.parent;
                    while (u.parent != null && u.numChildren == 1) {
                        ++v.quickCount[u.parentChar];
                        u.quickChild = v;
                        u = u.parent;
                    }
                    v.quickParent = u;
                    for (int i = 0; i < 26; ++i) {
                        u.subtreeCount[i] = Math.max(u.subtreeCount[i], v.subtreeCount[i] + v.quickCount[i]);
                    }
                    v.childIndex = v.quickParent.numInterestingChildren++;
                }
            }
            for (TaskD.Vertex v : interesting) {
                v.heap = new TaskD.Heap[26];
                for (int i = 0; i < 26; ++i) {
                    v.heap[i] = new TaskD.Heap(v.numInterestingChildren);
                }
            }
            for (TaskD.Vertex v : interesting) {
                for (int i = 0; i < 26; ++i) {
                    v.heap[i].heapify();
                }
                if (v.parent != null) {
                    TaskD.Vertex u = v.quickParent;
                    for (int i = 0; i < 26; ++i) {
                        u.heap[i].heap[v.childIndex] = v.childIndex;
                        u.heap[i].inHeap[v.childIndex] = v.childIndex;
                        u.heap[i].val[v.childIndex] = v.subtreeCount[i] + v.quickCount[i];
                    }
                }
            }
            for (int qi = 0; qi < q; ++qi) {
                TaskD.Vertex u = vs[in.nextInt() - 1];
                TaskD.Vertex v = u.quickChild;
                int c1 = u.parentChar;
                char ch = in.next().charAt(0);
                int c2;
                if (ch == '?') {
                    c2 = WILDCARD;
                } else {
                    c2 = ch - 'a';
                }
                if (c1 != c2) {
                    u.parentChar = c2;
                    if (c1 < 26) {
                        propagate(v, c1, v.subtreeCount[c1] + v.quickCount[c1] - 1);
                        --v.quickCount[c1];
                    }
                    if (c2 < 26) {
                        propagate(v, c2, v.subtreeCount[c2] + v.quickCount[c2] + 1);
                        ++v.quickCount[c2];
                    }
                }
                if (numInvalid == 0) {
                    int s = 0;
                    int spare = leafDepth - vs[0].subtreeSum;
                    for (int i = 0; i < 26; ++i) {
                        s += (i + 1) * (vs[0].subtreeCount[i] + spare);
                    }
                    out.println("Shi " + s);
                } else {
                    out.println("Fou");
                }
            }
        }

        private void propagate(TaskD.Vertex v, int what, int to) {
            TaskD.Vertex u = v.quickParent;
            if (u.subtreeSum > leafDepth - u.depth) {
                --numInvalid;
            }
            int old = u.subtreeCount[what];
            u.subtreeSum -= old;
            u.heap[what].val[u.heap[what].inHeap[v.childIndex]] = to;
            u.heap[what].heapUp(u.heap[what].inHeap[v.childIndex]);
            u.heap[what].heapDown(u.heap[what].inHeap[v.childIndex]);
            u.subtreeCount[what] = u.heap[what].val[0];
            u.subtreeSum += u.subtreeCount[what];
            if (u.subtreeSum > leafDepth - u.depth) {
                ++numInvalid;
            }
            if (u.parent != null && u.subtreeCount[what] != old) {
                propagate(u, what, u.subtreeCount[what] + u.quickCount[what]);
            }
        }

        private void reverseArray(TaskD.Vertex[] a) {
            for (int i = 0, j = a.length - 1; i < j; ++i, --j) {
                TaskD.Vertex t = a[i];
                a[i] = a[j];
                a[j] = t;
            }
        }

        static class Heap {
            int n;
            int[] val;
            int[] heap;
            int[] inHeap;

            public Heap(int n) {
                this.n = n;
                val = new int[n];
                heap = new int[n];
                inHeap = new int[n];
            }

            public void heapify() {
                for (int i = n - 1; i >= 0; --i) {
                    heapDown(i);
                }
            }

            private void heapDown(int at) {
                while (true) {
                    int i = at;
                    if (2 * at + 1 < n && val[2 * at + 1] > val[i]) i = 2 * at + 1;
                    if (2 * at + 2 < n && val[2 * at + 2] > val[i]) i = 2 * at + 2;
                    if (i == at) break;
                    heapSwap(at, i);
                    at = i;
                }
            }

            private void heapUp(int at) {
                while (at > 0) {
                    int p = (at - 1) / 2;
                    if (val[p] >= val[at]) break;
                    heapSwap(at, p);
                    at = p;
                }
            }

            private void heapSwap(int a, int b) {
                int t = heap[a];
                heap[a] = heap[b];
                heap[b] = t;
                t = val[a];
                val[a] = val[b];
                val[b] = t;
                inHeap[heap[a]] = a;
                inHeap[heap[b]] = b;
            }

        }

        static class Vertex {
            TaskD.Vertex parent;
            int parentChar;
            int depth;
            int numChildren;
            TaskD.Vertex quickParent;
            TaskD.Vertex quickChild;
            int[] quickCount;
            int[] subtreeCount;
            int numInterestingChildren;
            int childIndex;
            TaskD.Heap[] heap;
            int subtreeSum;

        }

    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

    }
}


#include<stdio.h>
#include<bits/stdc++.h>

using namespace std;
const int maxn = 150005;
vector<int>ve[maxn],so[maxn];
int n,q;
char ss[10];
char ch[maxn];
int len[maxn],dylf[maxn],fa[maxn];

int dfs(int x) {
	int son = 0;
	for(auto y:ve[x]) {
		dylf[x] = dfs(y);
		if(len[x]&&len[y]+1!=len[x]) {
			for(int i=1;i<=q;i++) puts("Fou");
			exit(0);
		} else len[x] = len[y] + 1;
		son++;
	}
	if(!son) dylf[x] = x;
	else if((x==0)||son>1) {
		dylf[x] = x;
		for(auto y:ve[x]) fa[dylf[y]] = x , so[x].push_back(dylf[y]);
	}
	return dylf[x];
}
int BAN;
int dp[maxn][26];
int cc[maxn][26],sum[maxn];
void upd(int x,int y,int z) {
	cc[x][y] += z;
	for(int o=fa[x];o!=-1;o=fa[o]) {
		BAN -= ( sum[o] > len[o] );
		sum[o] -= dp[o][y];
		dp[o][y] = 0;
		for(auto e:so[o]){
			dp[o][y] = max(dp[o][y],cc[e][y]+dp[e][y]);
		}
		sum[o] += dp[o][y];
		BAN += ( sum[o] > len[o] );
	}
}

int main() {
	scanf("%d%d",&n,&q);
	for(int i=2;i<=n;i++) {
		int x; scanf("%d",&x);
		ve[x].push_back(i);
		scanf("%s",&ss[1]);
		ch[i] = ss[1];
	}
	fa[0] = -1;
	ve[0].push_back(1);
	dfs(0);
	len[0]--;
	for(int i=2;i<=n;i++) {
		if(ch[i]!='?') upd(i,ch[i]-'a',+1);
	}
	for(int qi=1;qi<=q;qi++) {
		int x; scanf("%d%s",&x,&ss[1]);
		if(ch[x]!='?') upd(x,ch[x]-'a',-1);
		ch[x] = ss[1];
		if(ch[x]!='?') upd(x,ch[x]-'a',+1);
		if(BAN!=0) puts("Fou");
		else {
			long long ans = 0;
			for(int i=0;i<26;i++) {
				ans += 1ll*(i+1)*(len[0]-sum[0]+dp[0][i]);
			}
			printf("Shi %lld\n",ans);
		}
	}
}


#include<stdio.h>
#include<bits/stdc++.h>

using namespace std;
const int maxn = 150005;
vector<int>ve[maxn],so[maxn];
int n,q;
char ss[10];
char ch[maxn];
int len[maxn],dylf[maxn],fa[maxn];

int dfs(int x) {
	int son = 0;
	for(auto y:ve[x]) {
		dylf[x] = dfs(y);
		if(len[x]&&len[y]+1!=len[x]) {
			for(int i=1;i<=q;i++) puts("Fou");
			exit(0);
		} else len[x] = len[y] + 1;
		son++;
	}
	if(!son) dylf[x] = x;
	else if((x==0)||son>1) {
		dylf[x] = x;
		for(auto y:ve[x]) fa[dylf[y]] = x , so[x].push_back(dylf[y]);
	}
	return dylf[x];
}
int BAN;
int dp[maxn][26];
int cc[maxn][26],sum[maxn];
void upd(int x,int y,int z) {
	cc[x][y] += z;
	for(int o=fa[x];o!=-1;o=fa[o]) {
		BAN -= ( sum[o] > len[o] );
		sum[o] -= dp[o][y];
		dp[o][y] = 0;
		for(auto e:so[o]){
			dp[o][y] = max(dp[o][y],cc[e][y]+dp[e][y]);
		}
		sum[o] += dp[o][y];
		BAN += ( sum[o] > len[o] );
	}
}

int main() {
	scanf("%d%d",&n,&q);
	for(int i=2;i<=n;i++) {
		int x; scanf("%d",&x);
		ve[x].push_back(i);
		scanf("%s",&ss[1]);
		ch[i] = ss[1];
	}
	fa[0] = -1; len[0]--;
	ve[0].push_back(1);
	dfs(0);
	for(int i=2;i<=n;i++) {
		if(ch[i]!='?') upd(i,ch[i]-'a',+1);
	}
	for(int qi=1;qi<=q;qi++) {
		int x; scanf("%d%s",&x,&ss[1]);
		if(ch[x]!='?') upd(x,ch[x]-'a',-1);
		ch[x] = ss[1];
		if(ch[x]!='?') upd(x,ch[x]-'a',+1);
		if(BAN!=0) puts("Fou");
		else {
			long long ans = 0;
			for(int i=0;i<26;i++) {
				ans += 1ll*(i+1)*(len[0]-sum[0]+dp[0][i]);
			}
			printf("Shi %lld\n",ans);
		}
	}
}


#include<stdio.h>
#include<bits/stdc++.h>

using namespace std;
const int maxn = 150005;
vector<int>ve[maxn],so[maxn];
int n,q;
char ss[10];
char ch[maxn];
int len[maxn],dylf[maxn],fa[maxn];

int dfs(int x) {
	int son = 0;
	for(auto y:ve[x]) {
		dylf[x] = dfs(y);
		if(len[x]&&len[y]+1!=len[x]) {
			for(int i=1;i<=q;i++) puts("Fou");
			exit(0);
		} else len[x] = len[y] + 1;
		son++;
	}
	if(!son) dylf[x] = x;
	else if((x==0)||son>1) {
		dylf[x] = x;
		for(auto y:ve[x]) fa[dylf[y]] = x , so[x].push_back(dylf[y]);
	}
	return dylf[x];
}
int BAN;
int dp[maxn][26];
int cc[maxn][26],sum[maxn];
void upd(int x,int y,int z) {
	cc[x][y] += z;
	for(int o=fa[x];o!=-1;o=fa[o]) {
		BAN -= ( sum[o] > len[o] );
		sum[o] -= dp[o][y];
		dp[o][y] = 0;
		for(auto e:so[o]){
			dp[o][y] = max(dp[o][y],cc[e][y]+dp[e][y]);
		}
		sum[o] += dp[o][y];
		BAN += ( sum[o] > len[o] );
	}
}

int main() {
	scanf("%d%d",&n,&q);
	for(int i=2;i<=n;i++) {
		int x; scanf("%d",&x);
		ve[x].push_back(i);
		scanf("%s",&ss[1]);
		ch[i] = ss[1];
	}
	fa[0] = -1;
	ve[0].push_back(1);
	dfs(0);
	len[0]--;
	for(int i=2;i<=n;i++) {
		if(ch[i]!='?') upd(dylf[i],ch[i]-'a',+1);
	}
	for(int qi=1;qi<=q;qi++) {
		int x; scanf("%d%s",&x,&ss[1]);
		if(ch[x]!='?') upd(dylf[x],ch[x]-'a',-1);
		ch[x] = ss[1];
		if(ch[x]!='?') upd(dylf[x],ch[x]-'a',+1);
		if(BAN!=0) puts("Fou");
		else {
			long long ans = 0;
			for(int i=0;i<26;i++) {
				ans += 1ll*(i+1)*(len[0]-sum[0]+dp[0][i]);
			}
			printf("Shi %lld\n",ans);
		}
	}
}


#include<stdio.h>
#include<bits/stdc++.h>

using namespace std;
const int maxn = 150005;
vector<int>ve[maxn],so[maxn];
int n,q;
char ss[10];
char ch[maxn];
int len[maxn],dylf[maxn],fa[maxn];

int dfs(int x) {
	int son = 0;
	for(auto y:ve[x]) {
		dylf[x] = dfs(y);
		if(len[x]&&len[y]+1!=len[x]) {
			for(int i=1;i<=q;i++) puts("Fou");
			exit(0);
		} else len[x] = len[y] + 1;
		son++;
	}
	if(!son) dylf[x] = x;
	else if((x==0)||son>1) {
		dylf[x] = x;
		for(auto y:ve[x]) fa[dylf[y]] = x , so[x].push_back(dylf[y]);
	}
	return dylf[x];
}
int BAN;
int dp[maxn][26];
int cc[maxn][26],sum[maxn];
void upd(int x,int y,int z) {
	cc[x][y] += z;
	for(int o=fa[x];o!=-1;o=fa[o]) {
		BAN -= ( sum[o] > len[o] );
		sum[o] -= dp[o][y];
		dp[o][y] = 0;
		for(auto e:so[o]){
		dp[o][y] = max(dp[o][y],cc[e][y]+dp[e][y]);
	}
		sum[o] += dp[o][y];
		BAN += ( sum[o] > len[o] );
	}
}

int main() {
	scanf("%d%d",&n,&q);
	for(int i=2;i<=n;i++) {
		int x; scanf("%d",&x);
		ve[x].push_back(i);
		scanf("%s",&ss[1]);
		ch[i] = ss[1];
	}
	fa[0] = -1;
	ve[0].push_back(1);
	dfs(0);
	for(int i=2;i<=n;i++) {
		if(ch[i]!='?') upd(i,ch[i]-'a',+1);
	}
	for(int qi=1;qi<=q;qi++) {
		int x; scanf("%d%s",&x,&ss[1]);
		if(ch[x]!='?') upd(x,ch[x]-'a',-1);
		ch[x] = ss[1];
		if(ch[x]!='?') upd(x,ch[x]-'a',+1);
		if(BAN!=0) puts("Fou");
		else {
			long long ans = 0;
			for(int i=0;i<26;i++) {
				ans += 1ll*(i+1)*(len[0]-1-sum[0]+dp[0][i]);
			}
			printf("Shi %lld\n",ans);
		}
	}
}


#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
char c[MAXN];
int n, m, len, d[MAXN], f[MAXN], dp[MAXN][26], val[MAXN][26];
int cnt, sum[MAXN], depth[MAXN], father[MAXN];
vector <int> a[MAXN];
int F(int x) {
	if (f[x] == x) return x;
	else return f[x] = F(f[x]);
}
void work(int pos) {
	for (auto x : a[pos]) {
		work(x);
		for (int i = 0; i <= 25; i++)
			chkmax(dp[pos][i], dp[x][i]);
	}
	for (int i = 0; i <= 25; i++) {
		sum[pos] += dp[pos][i];
		dp[pos][i] += val[pos][i];
	}
	cnt += sum[pos] > len - depth[pos];
}
void update(int pos, int type) {
	cnt -= sum[pos] > len - depth[pos];
	dp[pos][type] -= val[pos][type];
	sum[pos] -= dp[pos][type], dp[pos][type] = 0;
	for (auto x : a[pos])
		chkmax(dp[pos][type], dp[x][type]);
	sum[pos] += dp[pos][type];
	dp[pos][type] += val[pos][type];
	cnt += sum[pos] > len - depth[pos];
	if (pos != 1) update(father[pos], type);
}
void printans() {
	int tot = 0;
	for (int i = 0; i <= 25; i++)
		tot += dp[1][i];
	if (cnt) {
		puts("Fou");
		return;
	}
	int ans = 0;
	for (int i = 0; i <= 25; i++)
		ans += (i + 1) * (len - tot + dp[1][i]);
	printf("Shi %d\n", ans);
}
int main() {
	read(n), read(m);
	for (int i = 2; i <= n; i++) {
		scanf("%d %c", &father[i], &c[i]);
		d[father[i]]++, depth[i] = depth[father[i]] + 1;
	}
	for (int i = 1; i <= n; i++)
		if (d[i] == 0) {
			if (len == 0) len = depth[i];
			else if (len != depth[i]) len = -1;
		}
	if (len == -1) {
		for (int i = 1; i <= m; i++)
			puts("Fou");
		return 0;
	}
	for (int i = 1; i <= n; i++)
		f[i] = i;
	for (int i = 2; i <= n; i++)
		if (father[i] != 1 && d[father[i]] == 1) {
			f[father[i]] = i;
			father[i] = father[father[i]];
		}
	for (int i = 2; i <= n; i++) {
		f[i] = F(i);
		if (f[i] == i) a[father[i]].push_back(i);
		if (c[i] != '?') val[f[i]][c[i] - 'a']++;
	}
	work(1);
	for (int i = 1; i <= m; i++) {
		int x; char s;
		scanf("%d %c", &x, &s);
		if (c[x] != '?') {
			val[f[x]][c[x] - 'a']--;
			dp[f[x]][c[x] - 'a']--;
			update(f[x], c[x] - 'a');
		}
		c[x] = s;
		if (c[x] != '?') {
			val[f[x]][c[x] - 'a']++;
			dp[f[x]][c[x] - 'a']++;
			update(f[x], c[x] - 'a');
		}
		printans();
	}
	return 0;
}


#include<bits/stdc++.h>
#include <cstring>
#include <iostream>
#define pie acos(-1)
#define si(a) scanf("%d",&a)
#define sii(a,b) scanf("%d %d",&a,&b)
#define siii(a,b,c) scanf("%d %d %d",&a,&b,&c)
#define sl(a) scanf("%lld",&a)
#define sll(a,b) scanf("%lld %lld",&a,&b)
#define slll(a,b,c) scanf("%lld %lld %lld",&a,&b,&c)
#define ss(st) scanf("%s",st)
#define sch(ch) scanf("%ch",&ch)
#define ps(a) printf("%s",a)
#define newLine() printf("\n")
#define pi(a) printf("%d",a)
#define pii(a,b) printf("%d %d",a,b)
#define piii(a,b,c) printf("%d %d %d",a,b,c)
#define pl(a) printf("%lld",a)
#define pll(a,b) printf("%lld %lld",a,b)
#define plll(a,b,c) printf("%lld %lld %lld",a,b,c)
#define pd(a) printf("%lf",a)
#define pdd(a,b) printf("%lf %lf",a,b)
#define pddd(a,b,c) printf("%lf %lf %lf",a,b,c)
#define pch(c) printf("%ch",c)
#define debug1(str,a) printf("%s=%d\n",str,a)
#define debug2(str1,str2,a,b) printf("%s=%d %s=%d\n",str1,a,str2,b)
#define debug3(str1,str2,str3,a,b,c) printf("%s=%d %s=%d %s=%d\n",str1,a,str2,b,str3,c)
#define debug4(str1,str2,str3,str4,a,b,c,d) printf("%s=%d %s=%d %s=%d %s=%d\n",str1,a,str2,b,str3,c,str4,d)
#define for0(i,n) for(i=0;i<n;i++)
#define for1(i,n) for(i=1;i<=n;i++)
#define forab(i,a,b) for(i=a;i<=b;i++)
#define forstl(i, s) for (__typeof ((s).end ()) i = (s).begin (); i != (s).end (); ++i)
#define nl puts("")
#define sd(a) scanf("%lf",&a)
#define sdd(a,b) scanf("%lf %lf",&a,&b)
#define sddd(a,b,c) scanf("%lf %lf %lf",&a,&b,&c)
#define sp printf(" ")
#define ll long long int
#define ull unsigned long long int
#define MOD 1000000007
#define mpr make_pair
#define pub(x) push_back(x)
#define pob(x) pop_back(x)
#define mem(ara,value) memset(ara,value,sizeof(ara))
#define INF INT_MAX / 2
#define eps 1e-9
#define checkbit(n, pos) (n & (1<<pos))
#define setbit(n, pos) (n  (1<<pos))
#define para(i,a,b,ara)\
for(i=a;i<=b;i++){\
    if(i!=0){printf(" ");}\
    cout<<ara[i];\
}\
printf("\n");
#define pvec(i,vec)\
for(i=0;i<vec.size();i++){\
    if(i!=0){printf(" ");}\
    cout<<vec[i];\
}\
printf("\n");
#define ppara(i,j,n,m,ara)\
for(i=0;i<n;i++){\
    for(j=0;j<m;j++){\
        if(j!=0){printf(" ");}\
        cout<<ara[i][j];\
    }\
    printf("\n");\
}
#define ppstructara(i,j,n,m,ara)\
for(i=0;i<n;i++){\
    printf("%d:\n",i);\
    for(j=0;j<m;j++){\
        cout<<ara[i][j];printf("\n");\
    }\
}
#define ppvec(i,j,n,vec)\
for(i=0;i<n;i++){\
    printf("%d:",i);\
    for(j=0;j<vec[i].size();j++){\
        if(j!=0){printf(" ");}\
        cout<<vec[i][j];\
    }\
    printf("\n");\
}
#define ppstructvec(i,j,n,vec)\
for(i=0;i<n;i++){\
    printf("%d:",i);\
    for(j=0;j<vec[i].size();j++){\
        cout<<vec[i][j];printf("\n");\
    }\
}
#define sara(i,a,b,ara)\
for(i=a;i<=b;i++){\
    scanf("%d",&ara[i]);\
}
#define pstructara(i,a,b,ara)\
for(i=a;i<=b;i++){\
    cout<<ara[i];nl;\
}
#define pstructvec(i,vec)\
for(i=0;i<vec.size();i++){\
    cout<<vec[i];nl;\
}
#define pstructstl(stl,x)\
for(__typeof(stl.begin()) it=stl.begin();it!=stl.end();++it){\
    x=*it;\
    cout<<x;nl;\
}\
nl;
#define pstl(stl)\
for(__typeof(stl.begin()) it=stl.begin();it!=stl.end();++it){\
    if(it!=stl.begin()){sp;}\
    pi(*it);\
}\
nl;
#define ppairvec(i,vec)\
for(i=0;i<vec.size();i++){\
    cout<<vec[i].first;sp;cout<<vec[i].second;printf("\n");\
}
#define ppairara(i,a,b,ara)\
for(i=a;i<=b;i++){\
    cout<<ara[i].first;sp;cout<<ara[i].second;printf("\n");\
}
#define pppairvec(i,j,n,vec)\
for(i=0;i<n;i++){\
    printf("%d:\n",i);\
    for(j=0;j<vec[i].size();j++){\
        cout<<vec[i][j].first;sp;cout<<vec[i][j].second;nl;\
    }\
}
#define pppairara(i,j,n,m,ara)\
for(i=0;i<n;i++){\
    printf("%d:\n",i);\
    for(j=0;j<m;j++){\
        cout<<ara[i][j].first;printf(" ");cout<<ara[i][j].second;nl;\
    }\
}
#define SZ 150010
using namespace std;
//bool status[100010];
//vector <int> prime;
//void siv(){
//    int N = 100005, i, j; prime.clear();
//    int sq = sqrt(N);
//    for(i = 4; i <= N; i += 2){ status[i] = true; }
//    for(i = 3; i <= sq; i+= 2){
//        if(status[i] == false){
//            for(j = i * i; j <= N; j += i){ status[j] = true; }
//        }
//    }
//    status[1] = true;
//    for1(i, N){ if(!status[i]){ prime.pub(i); } }
//}
struct TREE1{
    int mx, dif, data, mxLz, difLz;
}tree1[4 * SZ + 10][26];
struct TREE2{
    int mn, lz;
}tree2[4 * SZ + 10];
int hNo[SZ], hHd[SZ], hSz[SZ], hPos[SZ], cLink[SZ];
int sbtr[SZ], hCnt = 0, ndCnt = 0;
int n, q, parent[SZ], ht[SZ];
vector < pair <int, char > > adj[SZ];
int dpMx[SZ][26], dpMn[SZ][26], dpDif[SZ][26], dpData[SZ][26], mxht = -1, mnht = INF;
char wt[SZ];
bool global;
vector <int> vrtx;
void dfs(int src, int par, int d){
    int i, j, cnt = 0; sbtr[src] = 1, ht[src] = d;
    for(i = 0; i < 26; i++){ dpMx[src][i] = 0, dpMn[src][i] = INF; }
    for(i = 0; i < adj[src].size(); i++){
        int u = adj[src][i].first;
        char w = adj[src][i].second;
        if(u != par){
            cnt++;
            for(j = 0; j < 26; j++){ dpData[u][j] = w - 'a' == j ? dpData[src][j] + 1 : dpData[src][j]; }
            dfs(u, src, d + 1);
            wt[u] = w;
            sbtr[src] += sbtr[u];
            for(j = 0; j < 26; j++){
                int vl = w - 'a' == j ? dpMx[u][j] + 1 : dpMx[u][j];
                dpMx[src][j] = max(dpMx[src][j], vl);
                dpMn[src][j] = min(dpMn[src][j], vl);
            }
        }
    }
    if(cnt == 0){ mxht = max(mxht, ht[src]), mnht = min(mnht, ht[src]); }
    if(cnt == 2){ for(j = 0; j < 26; j++){ dpDif[src][j] = dpMx[src][j] - dpMn[src][j]; } }
    else{ for(j = 0; j < 26; j++){ dpDif[src][j] = INF; } }
}
void bldHld(int src, int par, bool f){
    int i, j, bg = -1, mx = -1, u; vrtx.push_back(src);
    if(f){ hCnt++, hHd[hCnt - 1] = src, hSz[hCnt - 1] = 0, cLink[hCnt - 1] = par; }
    hNo[src] = hCnt - 1, hPos[src] = ndCnt++, hSz[hCnt - 1]++;
    for(i = 0; i < adj[src].size(); i++){
        u = adj[src][i].first;
        if(u != par){ if(sbtr[u] > mx){ mx = sbtr[u], bg = u; } }
    }
    if(bg != -1){ bldHld(bg, src, false); }
    for(i = 0; i < adj[src].size(); i++){
        u = adj[src][i].first;
        if(u != par && u != bg){ bldHld(u, src, true); }
    }
}
void makeHld(){
    int i, j; mxht = 0, mnht = INF, dfs(0, -1, 0);
    hCnt = ndCnt = 0, vrtx.clear();
    bldHld(0, -1, true);
//    ps("dpMx -- >\n");
//    for(i = 0; i < n; i++){ pi(dpMx[i][0]); sp; } nl;
//    ps("dpMn -- >\n");
//    for(i = 0; i < n; i++){ pi(dpMn[i][0]); sp; } nl;
//    ps("dpDif -- >\n");
//    for(i = 0; i < n; i++){ pi(dpDif[i][0]); sp; } nl;
//    ps("dpData -- >\n");
//    for(i = 0; i < n; i++){ pi(dpData[i][0]); sp; } nl;
//    ps("HLD -- >\n");
//    pvec(i, vrtx);
//    for(i = 0; i < hCnt; i++){
//        pii(hHd[i], vrtx[hPos[hHd[i]] + hSz[i] - 1]); nl;
//    }
}
void input(){
    int i, j;
    sii(n, q);
    for(i = 1; i < n; i++){
        int u, v; char w;  scanf("%d %c", & parent[i], & w);
        u = --parent[i], v = i, adj[u].push_back(mpr(v, w)), adj[v].push_back(mpr(u, w));
    }
}
void mrg1(int iter, int w){
    tree1[iter][w].mx = max(tree1[2 * iter + 1][w].mx, tree1[2 * iter + 2][w].mx);
    tree1[iter][w].dif = min(tree1[2 * iter + 1][w].dif, tree1[2 * iter + 2][w].dif);
}
void lazyUp1(int iter, int w, int mx, int df, int dt){
    tree1[iter][w].mx += mx;
    tree1[iter][w].mxLz += mx;
    tree1[iter][w].dif += df;
    tree1[iter][w].difLz += df;
    tree1[iter][w].data += dt;
}
void pushDown1(int iter, int w){
    lazyUp1(2 * iter + 1, w, tree1[iter][w].mxLz, tree1[iter][w].difLz, tree1[iter][w].data);
    lazyUp1(2 * iter + 2, w, tree1[iter][w].mxLz, tree1[iter][w].difLz, tree1[iter][w].data);
    tree1[iter][w].mxLz = tree1[iter][w].difLz = tree1[iter][w].data = 0;
}
void update1(int lo, int hi, int iter, int l, int r, int w, int mx, int df, int dt){
    if(l > r){ return; }
    int i, j, mid = (lo + hi) >> 1;
    if(l <= lo && r >= hi){ lazyUp1(iter, w, mx, df, dt); return; }
    else if(l > hi || r < lo){ return; }
    else{
        pushDown1(iter, w);
        update1(lo, mid, 2 * iter + 1, l, r, w, mx, df, dt);
        update1(mid + 1, hi, 2 * iter + 2, l, r, w, mx, df, dt);
        mrg1(iter, w);
    }
}
void mrg2(int iter){
    tree2[iter].mn = min(tree2[2 * iter + 1].mn, tree2[2 * iter + 2].mn);
}
void lazyUp2(int iter, int vl){
    tree2[iter].mn += vl;
    tree2[iter].lz += vl;
}
void pushDown2(int iter){
    lazyUp2(2 * iter + 1, tree2[iter].lz);
    lazyUp2(2 * iter + 2, tree2[iter].lz);
    tree2[iter].lz = 0;
}
void update2(int lo, int hi, int iter, int l, int r, int vl){
    if(l > r){ return; }
    int i, j, mid = (lo + hi) >> 1;
    if(l <= lo && r >= hi){ lazyUp2(iter, vl); return; }
    else if(l > hi || r < lo){ return; }
    else{
        pushDown2(iter);
        update2(lo, mid, 2 * iter + 1, l, r, vl);
        update2(mid + 1, hi, 2 * iter + 2, l, r, vl);
        mrg2(iter);
    }
}
tuple <int, int, int> query(int lo, int hi, int iter, int l, int r, int w){
    int i, j, mid = (lo + hi) >> 1;
    if(l <= lo && r >= hi){ return make_tuple(tree1[iter][w].mx, tree1[iter][w].dif, tree1[iter][w].data); }
    else if(l > hi || r < lo){ return make_tuple(-INF, INF, 0); }
    else{
        pushDown1(iter, w);
        tuple <int, int, int> retl = query(lo, mid, 2 * iter + 1, l, r, w);
        tuple <int, int, int> retr = query(mid + 1, hi, 2 * iter + 2, l, r, w);
        mrg1(iter, w);
        return make_tuple(max(get <0> (retl), get <0> (retr)), min(get <1> (retl), get <1> (retr)), get <2> (retl) + get <2> (retr));
    }
}
int kthParent(int u, int k){
    int i, j, v = u;
    while(1){
        int no = hNo[v];
        int hd = hHd[no];
        if(ht[u] - ht[hd] >= k){
            int dis = k - (ht[u] - ht[v]);
            return vrtx[hPos[v] - dis];
        }
        v = cLink[no];
    }
    return -1;
}
int getRange(int u, int w){
    int lo = 0, hi = ht[u], mid;
    tuple <int, int, int> ret = query(0, n - 1, 0, hPos[u], hPos[u], w);
    int d1 = get <2> (ret), offst = get <0> (ret), d2, d, v, chk;
    while(lo < hi){
        mid = (lo + hi + 1) >> 1;
        v = kthParent(u, mid);
        ret = query(0, n - 1, 0, hPos[v], hPos[v], w);
        d2 = get <2> (ret);
        d = d1 - d2;
        d += offst;
        chk = get <0> (ret);
        if(d >= chk){ lo = mid; }
        else{ hi = mid - 1; }
    }
    return lo;
}
void add(int u, int w){
    int i, j, v = parent[u];
    int k = getRange(u, w);
//    pi(k); nl;
//    pi(tree2[0].mn); nl;
    while(1){
        int no = hNo[v];
        int hd = hHd[no];
//        cout << "v -- > " << v << " " << "hd -- > " << hd; nl;
        if(ht[u] - ht[hd] >= k){
            int dis = k - (ht[u] - ht[v]);
//            pii(hPos[v] - dis, hPos[v]); nl;
            update1(0, n - 1, 0, hPos[v] - dis, hPos[v], w, 1, 1, 0);
            update2(0, n - 1, 0, hPos[v] - dis, hPos[v], -1);
            if(ht[u] - ht[hd] == k){
                if(no != 0){
                    v = cLink[no];
                    update1(0, n - 1, 0, hPos[v], hPos[v], w, 0, -1, 0);
                }
            }
            else{
                update1(0, n - 1, 0, hPos[v] - dis - 1, hPos[v] - dis - 1, w, 0, -1, 0);
            }
            break;
        }
        update1(0, n - 1, 0, hPos[hd], hPos[v], w, 1, 1, 0);
        update2(0, n - 1, 0, hPos[hd], hPos[v], -1);
        v = cLink[no];
    }
    update1(0, n - 1, 0, hPos[u], hPos[u] + sbtr[u] - 1, w, 0, 0, 1);
//    pi(tree2[0].mn); nl;
    wt[u] = (char)(w + 'a');
}
int subQuery(int lo, int hi, int iter, int w){
    int i, j, mid = (lo + hi) >> 1, ret;
    if(lo == hi){ return lo; }
    pushDown1(iter, w);
    if(tree1[2 * iter + 2][w].dif == 0){ ret = subQuery(mid + 1, hi, 2 * iter + 2, w); }
    else{ ret = subQuery(lo, mid, 2 * iter + 1, w); }
    mrg1(iter, w);
    return ret;
}
int zroQuery(int lo, int hi, int iter, int l, int r, int w){
    int i, j, mid = (lo + hi) >> 1;
    if(l <= lo && r >= hi){
        if(!global && tree1[iter][w].dif == 0){
            global = true;
            return subQuery(lo, hi, iter, w);
        }
        return -1;
    }
    else if(l > hi || r < lo){ return -1; }
    else{
        pushDown1(iter, w);
        int retr = zroQuery(mid + 1, hi, 2 * iter + 2, l, r, w);
        int retl = zroQuery(lo, mid, 2 * iter + 1, l, r, w);
        mrg1(iter, w);
        return max(retl, retr);
    }
}
void rmv(int u, int w){
    int i, j, v = parent[u], idx;
    int k = getRange(u, w);
    tuple <int, int, int> ret;
    while(1){
        int no = hNo[v];
        int hd = hHd[no];
        if(ht[u] - ht[hd] >= k){
            global = false;
            int dis = k - (ht[u] - ht[v]);
            ret = query(0, n - 1, 0, hPos[v] - dis, hPos[v], w);
            if(get <1> (ret) == 0){
                global = false, idx = zroQuery(0, n - 1, 0, hPos[v] - dis, hPos[v], w);
                update1(0, n - 1, 0, idx, hPos[v], w, -1, -1, 0);
                update2(0, n - 1, 0, idx, hPos[v], 1);
                if(vrtx[idx] == hd){
                    if(no != 0){
                        v = cLink[no];
                        update1(0, n - 1, 0, hPos[v], hPos[v], w, 0, 1, 0);
                    }
                }
                else{
                    update1(0, n - 1, 0, idx - 1, idx - 1, w, 0, 1, 0);
                }
                break;
            }
            else{
                update1(0, n - 1, 0, hPos[v] - dis, hPos[v], w, -1, -1, 0);
                update2(0, n - 1, 0, hPos[v] - dis, hPos[v], 1);
                if(ht[u] - ht[hd] == k){
                    if(no != 0){
                        v = cLink[no];
                        update1(0, n - 1, 0, hPos[v], hPos[v], w, 0, 1, 0);
                    }
                }
                else{
                    update1(0, n - 1, 0, hPos[v] - dis - 1, hPos[v] - dis - 1, w, 0, 1, 0);
                }
                break;
            }
        }
        ret = query(0, n - 1, 0, hPos[hd], hPos[v], w);
        if(get <1> (ret) == 0){
            global = false, idx = zroQuery(0, n - 1, 0, hPos[hd], hPos[v], w);
            update1(0, n - 1, 0, idx, hPos[v], w, -1, -1, 0);
            update2(0, n - 1, 0, idx, hPos[v], 1);
            if(vrtx[idx] == hd){
                if(no != 0){
                    v = cLink[no];
                    update1(0, n - 1, 0, hPos[v], hPos[v], w, 0, 1, 0);
                }
            }
            else{
                update1(0, n - 1, 0, idx - 1, idx - 1, w, 0, 1, 0);
            }
            break;
        }
        update1(0, n - 1, 0, hPos[hd], hPos[v], w, -1, -1, 0);
        update2(0, n - 1, 0, hPos[hd], hPos[v], 1);
        v = cLink[no];
    }
    update1(0, n - 1, 0, hPos[u], hPos[u] + sbtr[u] - 1, w, 0, 0, -1);
    wt[u] = '?';
}
void makeTree(int lo, int hi, int iter){
    int i, j, mid = (lo + hi) >> 1, sm = 0;
    if(lo == hi){
        for(i = 0; i < 26; i++){
            tree1[iter][i].mx = dpMx[vrtx[lo]][i];
            tree1[iter][i].dif = dpDif[vrtx[lo]][i];
            tree1[iter][i].data = dpData[vrtx[lo]][i];
            sm += tree1[iter][i].mx;
        }
        tree2[iter].mn = mxht - ht[vrtx[lo]] - sm;
    }
    else if(lo < hi){
        makeTree(lo, mid, 2 * iter + 1);
        makeTree(mid + 1, hi, 2 * iter + 2);
        for(i = 0; i < 26; i++){ mrg1(iter, i); }
        mrg2(iter);
    }
}
void solve(){
    int i, j, cnt = 0; makeHld();
    makeTree(0, n - 1, 0);
    for(i = 0; i < q; i++){
        int u; char w; scanf("%d %c", &u, &w); u--;
        if(wt[u] == '?' && w != '?'){
            add(u, w - 'a');
        }
        else if(wt[u] != '?' && w == '?'){
            rmv(u, wt[u] - 'a');
        }
        else if(wt[u] != '?' && w != '?'){
            rmv(u, wt[u] - 'a');
            add(u, w - 'a');
        }
        else if(wt[u] == '?' && w == '?'){}
        if(tree2[0].mn < 0){
            ps("Fou\n");
        }
        else{
            ps("Shi ");
            int sum = 0;
            for(j = 0; j < 26; j++){
                sum += tree1[0][j].mx;
            }
            for(j = 0, cnt = 0; j < 26; j++){
                cnt += (j + 1) * (tree1[0][j].mx + mxht - sum);
            }
            pi(cnt); nl;
        }
    }
}
int main(){
//    freopen("input.txt","r",stdin);
//    freopen("output.txt", "w", stdout);
    input();
    solve();
}


#include<bits/stdc++.h>
#include <cstring>
#include <iostream>
#define pie acos(-1)
#define si(a) scanf("%d",&a)
#define sii(a,b) scanf("%d %d",&a,&b)
#define siii(a,b,c) scanf("%d %d %d",&a,&b,&c)
#define sl(a) scanf("%lld",&a)
#define sll(a,b) scanf("%lld %lld",&a,&b)
#define slll(a,b,c) scanf("%lld %lld %lld",&a,&b,&c)
#define ss(st) scanf("%s",st)
#define sch(ch) scanf("%ch",&ch)
#define ps(a) printf("%s",a)
#define newLine() printf("\n")
#define pi(a) printf("%d",a)
#define pii(a,b) printf("%d %d",a,b)
#define piii(a,b,c) printf("%d %d %d",a,b,c)
#define pl(a) printf("%lld",a)
#define pll(a,b) printf("%lld %lld",a,b)
#define plll(a,b,c) printf("%lld %lld %lld",a,b,c)
#define pd(a) printf("%lf",a)
#define pdd(a,b) printf("%lf %lf",a,b)
#define pddd(a,b,c) printf("%lf %lf %lf",a,b,c)
#define pch(c) printf("%ch",c)
#define debug1(str,a) printf("%s=%d\n",str,a)
#define debug2(str1,str2,a,b) printf("%s=%d %s=%d\n",str1,a,str2,b)
#define debug3(str1,str2,str3,a,b,c) printf("%s=%d %s=%d %s=%d\n",str1,a,str2,b,str3,c)
#define debug4(str1,str2,str3,str4,a,b,c,d) printf("%s=%d %s=%d %s=%d %s=%d\n",str1,a,str2,b,str3,c,str4,d)
#define for0(i,n) for(i=0;i<n;i++)
#define for1(i,n) for(i=1;i<=n;i++)
#define forab(i,a,b) for(i=a;i<=b;i++)
#define forstl(i, s) for (__typeof ((s).end ()) i = (s).begin (); i != (s).end (); ++i)
#define nl puts("")
#define sd(a) scanf("%lf",&a)
#define sdd(a,b) scanf("%lf %lf",&a,&b)
#define sddd(a,b,c) scanf("%lf %lf %lf",&a,&b,&c)
#define sp printf(" ")
#define ll long long int
#define ull unsigned long long int
#define MOD 1000000007
#define mpr make_pair
#define pub(x) push_back(x)
#define pob(x) pop_back(x)
#define mem(ara,value) memset(ara,value,sizeof(ara))
#define INF INT_MAX / 2
#define eps 1e-9
#define checkbit(n, pos) (n & (1<<pos))
#define setbit(n, pos) (n  (1<<pos))
#define para(i,a,b,ara)\
for(i=a;i<=b;i++){\
    if(i!=0){printf(" ");}\
    cout<<ara[i];\
}\
printf("\n");
#define pvec(i,vec)\
for(i=0;i<vec.size();i++){\
    if(i!=0){printf(" ");}\
    cout<<vec[i];\
}\
printf("\n");
#define ppara(i,j,n,m,ara)\
for(i=0;i<n;i++){\
    for(j=0;j<m;j++){\
        if(j!=0){printf(" ");}\
        cout<<ara[i][j];\
    }\
    printf("\n");\
}
#define ppstructara(i,j,n,m,ara)\
for(i=0;i<n;i++){\
    printf("%d:\n",i);\
    for(j=0;j<m;j++){\
        cout<<ara[i][j];printf("\n");\
    }\
}
#define ppvec(i,j,n,vec)\
for(i=0;i<n;i++){\
    printf("%d:",i);\
    for(j=0;j<vec[i].size();j++){\
        if(j!=0){printf(" ");}\
        cout<<vec[i][j];\
    }\
    printf("\n");\
}
#define ppstructvec(i,j,n,vec)\
for(i=0;i<n;i++){\
    printf("%d:",i);\
    for(j=0;j<vec[i].size();j++){\
        cout<<vec[i][j];printf("\n");\
    }\
}
#define sara(i,a,b,ara)\
for(i=a;i<=b;i++){\
    scanf("%d",&ara[i]);\
}
#define pstructara(i,a,b,ara)\
for(i=a;i<=b;i++){\
    cout<<ara[i];nl;\
}
#define pstructvec(i,vec)\
for(i=0;i<vec.size();i++){\
    cout<<vec[i];nl;\
}
#define pstructstl(stl,x)\
for(__typeof(stl.begin()) it=stl.begin();it!=stl.end();++it){\
    x=*it;\
    cout<<x;nl;\
}\
nl;
#define pstl(stl)\
for(__typeof(stl.begin()) it=stl.begin();it!=stl.end();++it){\
    if(it!=stl.begin()){sp;}\
    pi(*it);\
}\
nl;
#define ppairvec(i,vec)\
for(i=0;i<vec.size();i++){\
    cout<<vec[i].first;sp;cout<<vec[i].second;printf("\n");\
}
#define ppairara(i,a,b,ara)\
for(i=a;i<=b;i++){\
    cout<<ara[i].first;sp;cout<<ara[i].second;printf("\n");\
}
#define pppairvec(i,j,n,vec)\
for(i=0;i<n;i++){\
    printf("%d:\n",i);\
    for(j=0;j<vec[i].size();j++){\
        cout<<vec[i][j].first;sp;cout<<vec[i][j].second;nl;\
    }\
}
#define pppairara(i,j,n,m,ara)\
for(i=0;i<n;i++){\
    printf("%d:\n",i);\
    for(j=0;j<m;j++){\
        cout<<ara[i][j].first;printf(" ");cout<<ara[i][j].second;nl;\
    }\
}
#define SZ 150010
using namespace std;
//bool status[100010];
//vector <int> prime;
//void siv(){
//    int N = 100005, i, j; prime.clear();
//    int sq = sqrt(N);
//    for(i = 4; i <= N; i += 2){ status[i] = true; }
//    for(i = 3; i <= sq; i+= 2){
//        if(status[i] == false){
//            for(j = i * i; j <= N; j += i){ status[j] = true; }
//        }
//    }
//    status[1] = true;
//    for1(i, N){ if(!status[i]){ prime.pub(i); } }
//}
int n, q;
vector < pair <int, char > > gr[SZ];
vector <int> adj[SZ];
vector <int> vrtx;
int wt[SZ][26], ht[SZ], mxht = -1, mnht = INF, parent[SZ], thresh;
int dpMx[SZ][26], dpMn[SZ][26], dpDif[SZ][26], dp[SZ], link[SZ];
char pvwt[SZ];
vector <int> sv;
void dfs(int src, int par, int d);
void input(){
    int i, j;
    sii(n, q);
    for(i = 1; i < n; i++){
        int u, v; char w; scanf("%d %c", &u, &w);
        u--; v = i; gr[u].push_back(mpr(v, w)), gr[v].push_back(mpr(u, w));
        pvwt[v] = w;
    }
}
void compress(int cnn, int src, int par, char w, int d){
    int i, j, cnt = 0, u; ht[src] = d;
    char nw;
    sv.push_back(src);
    for(i = 0; i < gr[src].size(); i++){
        u = gr[src][i].first;
        if(u != par){ cnt++; nw = gr[src][i].second; }
    }
    if(cnn == par){ for(i = 0; i < 26; i++){ wt[src][i] = w - 'a' == i ? 1 : 0; } }
    else{ for(i = 0; i < 26; i++){ wt[src][i] = w - 'a' == i ? wt[par][i] + 1 : wt[par][i]; } }
    if(cnt == 1){ compress(cnn, u, src, nw, d + 1); }
    else{
        for(i = 0; i < sv.size(); i++){ link[sv[i]] = src; } sv.clear();
        adj[cnn].push_back(src), adj[src].push_back(cnn); dfs(src, par, d);
    }
}
void dfs(int src, int par, int d){
    int i, j, cnt = 0; ht[src] = d, vrtx.push_back(src);
    for(i = 0; i < gr[src].size(); i++){
        int u = gr[src][i].first;
        char w = gr[src][i].second;
        if(u != par){
            cnt++;
            compress(src, u, src, w, d + 1);
        }
    }
    if(cnt == 0){ mxht = max(mxht, d), mnht = min(mnht, d); }
}
void F(int src, int par){
    int i, j, cnt = 0; dp[src] = mxht - ht[src]; parent[src] = par;
    for(i = 0; i < 26; i++){ dpMx[src][i] = 0, dpMn[src][i] = INF, dpDif[src][i] = INF; }
    for(i = 0; i < adj[src].size(); i++){
        int u = adj[src][i];
        if(u != par){
            F(u, src); cnt++;
            for(j = 0; j < 26; j++){
                dpMx[src][j] = max(dpMx[src][j], wt[u][j] + dpMx[u][j]);
                dpMn[src][j] = min(dpMn[src][j], wt[u][j] + dpMx[u][j]);
            }
        }
    }
    for(i = 0; i < 26; i++){
        dp[src] -= dpMx[src][i];
    }
    if(cnt == 2){
        for(i = 0; i < 26; i++){ dpDif[src][i] = dpMx[src][i] - dpMn[src][i]; }
    }
}
void rec1(int respect, int u, int w, int cnt){
    if(u == -1){ return; }
    if(cnt + dpMx[respect][w] >= dpMx[u][w]){
        dpMx[u][w]++, dpDif[u][w]++, dp[u]--;
        if(dp[u] == -1){ thresh++; }
        rec1(respect, parent[u], w, cnt + wt[u][w]);
    }
    else{ dpDif[u][w]--; return; }
}
void add(int u, int w){
    int i, j;
    rec1(u, parent[u], w, wt[u][w]);
    wt[u][w]++;
}
void rec2(int respect, int u, int w, int cnt){
    if(u == -1){ return; }
    if(cnt + dpMx[respect][w] >= dpMx[u][w] && dpDif[u][w] > 0){
        dpMx[u][w]--, dpDif[u][w]--, dp[u]++;
        if(dp[u] == 0){ thresh--; }
        rec2(respect, parent[u], w, cnt + wt[u][w]);
    }
    else{ dpDif[u][w]++; return; }
}
void dlt(int u, int w){
    int i, j;
    rec2(u, parent[u], w, wt[u][w]);
    wt[u][w]--;
}
void solve(){
    int i, j;
    mxht = -1, mnht = INF, dfs(0, - 1, 0);
//    ppvec(i, j, n, adj);
    F(0, -1);
//    pvec(i, vrtx);
//    cout << "dpMx -- >\n";
//    for(i = 0; i < vrtx.size(); i++){
//        int u = vrtx[i];
//        pi(dpMx[u][0]); sp;
//    }
//    nl;
//    cout << "dpMn -- >\n";
//    for(i = 0; i < vrtx.size(); i++){
//        int u = vrtx[i];
//        pi(dpMn[u][0]); sp;
//    }
//    nl;
//    cout << "dpDif -- >\n";
//    for(i = 0; i < vrtx.size(); i++){
//        int u = vrtx[i];
//        pi(dpDif[u][0]); sp;
//    }
//    nl;
//    cout << "dp -- >\n";
//    for(i = 0; i < vrtx.size(); i++){
//        int u = vrtx[i];
//        pi(dp[u]); sp;
//    }
//    nl;
//    for(i = 0, thresh = 0; i < vrtx.size(); i++){ if(dp[i] < 0){ thresh++; } }
//    cout << "query -- >"; nl;
    int cnt = 0;
    for(i = 0; i < q; i++){
        int u; char w; scanf("%d %c", &u, &w); u--;
        if(mxht != mnht){ ps("Fou\n"); continue; }
        if(pvwt[u] == '?' && w != '?'){
            add(link[u], w - 'a'); pvwt[u] = w;
        }
        else if(pvwt[u] != '?' && w == '?'){
            dlt(link[u], pvwt[u] - 'a'); pvwt[u] = '?';
        }
        else if(pvwt[u] != '?' && w != '?'){
            dlt(link[u], pvwt[u] - 'a'); pvwt[u] = '?';
            add(link[u], w - 'a'); pvwt[u] = w;
        }
//        cout << "after every query -- >"; nl;
//        for(j = 0; j < vrtx.size(); j++){
//            u = vrtx[j];
//            pii(dpMx[u][0], dp[u]); nl;
//        }
        if(thresh > 0){ ps("Fou\n"); }
        else{
            ps("Shi ");
            for(j = 0, cnt = 0; j < 26; j++){
                cnt += (j + 1) * (dpMx[0][j] + dp[0]);
            }
            pi(cnt); nl;
        }
    }
}
int main(){
//    freopen("input.txt","r",stdin);
//    freopen("output.txt", "w", stdout);
    input();
    solve();
}


#include<bits/stdc++.h>
#include <cstring>
#include <iostream>
#define pie acos(-1)
#define si(a) scanf("%d",&a)
#define sii(a,b) scanf("%d %d",&a,&b)
#define siii(a,b,c) scanf("%d %d %d",&a,&b,&c)
#define sl(a) scanf("%lld",&a)
#define sll(a,b) scanf("%lld %lld",&a,&b)
#define slll(a,b,c) scanf("%lld %lld %lld",&a,&b,&c)
#define ss(st) scanf("%s",st)
#define sch(ch) scanf("%ch",&ch)
#define ps(a) printf("%s",a)
#define newLine() printf("\n")
#define pi(a) printf("%d",a)
#define pii(a,b) printf("%d %d",a,b)
#define piii(a,b,c) printf("%d %d %d",a,b,c)
#define pl(a) printf("%lld",a)
#define pll(a,b) printf("%lld %lld",a,b)
#define plll(a,b,c) printf("%lld %lld %lld",a,b,c)
#define pd(a) printf("%lf",a)
#define pdd(a,b) printf("%lf %lf",a,b)
#define pddd(a,b,c) printf("%lf %lf %lf",a,b,c)
#define pch(c) printf("%ch",c)
#define debug1(str,a) printf("%s=%d\n",str,a)
#define debug2(str1,str2,a,b) printf("%s=%d %s=%d\n",str1,a,str2,b)
#define debug3(str1,str2,str3,a,b,c) printf("%s=%d %s=%d %s=%d\n",str1,a,str2,b,str3,c)
#define debug4(str1,str2,str3,str4,a,b,c,d) printf("%s=%d %s=%d %s=%d %s=%d\n",str1,a,str2,b,str3,c,str4,d)
#define for0(i,n) for(i=0;i<n;i++)
#define for1(i,n) for(i=1;i<=n;i++)
#define forab(i,a,b) for(i=a;i<=b;i++)
#define forstl(i, s) for (__typeof ((s).end ()) i = (s).begin (); i != (s).end (); ++i)
#define nl puts("")
#define sd(a) scanf("%lf",&a)
#define sdd(a,b) scanf("%lf %lf",&a,&b)
#define sddd(a,b,c) scanf("%lf %lf %lf",&a,&b,&c)
#define sp printf(" ")
#define ll long long int
#define ull unsigned long long int
#define MOD 1000000007
#define mpr make_pair
#define pub(x) push_back(x)
#define pob(x) pop_back(x)
#define mem(ara,value) memset(ara,value,sizeof(ara))
#define INF INT_MAX
#define eps 1e-9
#define checkbit(n, pos) (n & (1<<pos))
#define setbit(n, pos) (n  (1<<pos))
#define para(i,a,b,ara)\
for(i=a;i<=b;i++){\
    if(i!=0){printf(" ");}\
    cout<<ara[i];\
}\
printf("\n");
#define pvec(i,vec)\
for(i=0;i<vec.size();i++){\
    if(i!=0){printf(" ");}\
    cout<<vec[i];\
}\
printf("\n");
#define ppara(i,j,n,m,ara)\
for(i=0;i<n;i++){\
    for(j=0;j<m;j++){\
        if(j!=0){printf(" ");}\
        cout<<ara[i][j];\
    }\
    printf("\n");\
}
#define ppstructara(i,j,n,m,ara)\
for(i=0;i<n;i++){\
    printf("%d:\n",i);\
    for(j=0;j<m;j++){\
        cout<<ara[i][j];printf("\n");\
    }\
}
#define ppvec(i,j,n,vec)\
for(i=0;i<n;i++){\
    printf("%d:",i);\
    for(j=0;j<vec[i].size();j++){\
        if(j!=0){printf(" ");}\
        cout<<vec[i][j];\
    }\
    printf("\n");\
}
#define ppstructvec(i,j,n,vec)\
for(i=0;i<n;i++){\
    printf("%d:",i);\
    for(j=0;j<vec[i].size();j++){\
        cout<<vec[i][j];printf("\n");\
    }\
}
#define sara(i,a,b,ara)\
for(i=a;i<=b;i++){\
    scanf("%d",&ara[i]);\
}
#define pstructara(i,a,b,ara)\
for(i=a;i<=b;i++){\
    cout<<ara[i];nl;\
}
#define pstructvec(i,vec)\
for(i=0;i<vec.size();i++){\
    cout<<vec[i];nl;\
}
#define pstructstl(stl,x)\
for(__typeof(stl.begin()) it=stl.begin();it!=stl.end();++it){\
    x=*it;\
    cout<<x;nl;\
}\
nl;
#define pstl(stl)\
for(__typeof(stl.begin()) it=stl.begin();it!=stl.end();++it){\
    if(it!=stl.begin()){sp;}\
    pi(*it);\
}\
nl;
#define ppairvec(i,vec)\
for(i=0;i<vec.size();i++){\
    cout<<vec[i].first;sp;cout<<vec[i].second;printf("\n");\
}
#define ppairara(i,a,b,ara)\
for(i=a;i<=b;i++){\
    cout<<ara[i].first;sp;cout<<ara[i].second;printf("\n");\
}
#define pppairvec(i,j,n,vec)\
for(i=0;i<n;i++){\
    printf("%d:\n",i);\
    for(j=0;j<vec[i].size();j++){\
        cout<<vec[i][j].first;sp;cout<<vec[i][j].second;nl;\
    }\
}
#define pppairara(i,j,n,m,ara)\
for(i=0;i<n;i++){\
    printf("%d:\n",i);\
    for(j=0;j<m;j++){\
        cout<<ara[i][j].first;printf(" ");cout<<ara[i][j].second;nl;\
    }\
}
#define SZ 150010
using namespace std;
//bool status[100010];
//vector <int> prime;
//void siv(){
//    int N = 100005, i, j; prime.clear();
//    int sq = sqrt(N);
//    for(i = 4; i <= N; i += 2){ status[i] = true; }
//    for(i = 3; i <= sq; i+= 2){
//        if(status[i] == false){
//            for(j = i * i; j <= N; j += i){ status[j] = true; }
//        }
//    }
//    status[1] = true;
//    for1(i, N){ if(!status[i]){ prime.pub(i); } }
//}
int add(int _a, int _b){
    _a = (_a + MOD) % MOD;
    _b = (_b + MOD) % MOD;
    return (_a + _b) % MOD;
}
int mul(int _a, int _b){
    _a = (_a + MOD) % MOD;
    _b = (_b + MOD) % MOD;
    return ((ll)((ll)_a * (ll)_b)) % MOD;
}
int n, q, tmm = 0, pos[SZ], sbtr[SZ], buf[30], lfCnt = 0, ara[SZ], rating[SZ], mp[SZ], p[SZ], ht[SZ];
int frq[SZ][30], qstn[SZ], tree[4 * SZ + 10][27], lz[4 * SZ + 10][27];
char wt[SZ];
vector <pair <int, char > > adj[SZ];
void input(){
    int i, j;
    sii(n, q);
//    pii(n, q); nl;
    for(i = 1; i < n; i++){
        int u, v; char ch; scanf("%d %c", &v, &ch), u = i, v--, p[i - 1] = v;
        adj[u].push_back(mpr(v, ch)), adj[v].push_back(mpr(u, ch));
    }
//    pppairvec(i, j, n, adj);
}
void dfs(int src, int par, int qs, int d){
    int i, j; tmm++, pos[src] = tmm - 1, sbtr[src] = 1, ht[src] = d;
    bool f = false;
    for(i = 0; i < adj[src].size(); i++){
        int u = adj[src][i].first;
        char w = adj[src][i].second;
        if(u != par){
            f = true;
            buf[w - 'a']++; wt[u] = w;
            dfs(u, src, w == '?' ? qs + 1 : qs, d + 1);
            buf[w - 'a']--;
            sbtr[src] += sbtr[u];
        }
    }
    if(!f){
        ara[lfCnt] = src; rating[lfCnt] = pos[src], mp[src] = lfCnt;
        for(i = 0; i < 26; i++){ frq[lfCnt][i] = buf[i]; }
        qstn[lfCnt] = qs;
        lfCnt++;
    }
}
void mrg(int iter){
    int i, j;
    for(i = 0; i <= 26; i++){ tree[iter][i] = max(tree[2 * iter + 1][i], tree[2 * iter + 2][i]); }
}
void makeTree(int lo, int hi, int iter){
    int i, j, mid = (lo + hi) >> 1;
    if(lo == hi){
        for(i = 0; i < 26; i++){ tree[iter][i] = frq[lo][i]; }
        tree[iter][26] = qstn[lo]; return;
    }
    else if(lo < hi){
        makeTree(lo, mid, 2 * iter + 1);
        makeTree(mid + 1, hi, 2 * iter + 2);
        mrg(iter);
    }
}
void lazyUp(int iter, int mask[]){
    int i, j;
    for(i = 0; i <= 26; i++){ tree[iter][i] += mask[i]; lz[iter][i] += mask[i]; }
}
void pushDown(int iter){
    lazyUp(2 * iter + 1, lz[iter]);
    lazyUp(2 * iter + 2, lz[iter]);
    mem(lz[iter], 0);
}
void update(int lo, int hi, int iter, int l, int r, int mask[]){
    int i, j, mid = (lo + hi) >> 1;
    if(l <= lo && r >= hi){ lazyUp(iter, mask); return; }
    else if(l > hi || r < lo){ return; }
    else{
        pushDown(iter);
        update(lo, mid, 2 * iter + 1, l, r, mask);
        update(mid + 1, hi, 2 * iter + 2, l, r, mask);
        mrg(iter);
    }
}
void solve(){
    int i, j, vt, mask[27], l, r, sm, ret; mem(mask, 0);
    tmm = 0, lfCnt = 0, dfs(0, -1, 0, 0);
//    para(i, 0, lfCnt - 1, ara);
//    para(i, 0, lfCnt - 1, rating);
//    para(i, 0, n - 1, sbtr);
//    para(i, 0, n - 1, pos);
//    para(i, 0, n - 1, ht);
    makeTree(0, n - 1, 0);
//    pi(q); nl;
    bool f = false;
    for(i = 1; i < lfCnt; i++){
        if(ht[ara[i]] != ht[ara[i - 1]]){ f = true; break; }
    }
    for(i = 0; i < q; i++){
        int v, u; char ch; scanf("%d %c", &v, &ch); v--;
        if(f){ ps("Fou\n"); continue; }
//        printf("%d %c\n", v, ch);
        u = p[v - 1];
        if(ht[u] >= ht[v]){ vt = u; }
        else{ vt = v; }
        if(wt[vt] == '?'){ mask[26]--; }
        else{ mask[wt[vt] - 'a']--; }
        if(ch == '?'){ mask[26]++; }
        else{ mask[ch - 'a']++; }
        wt[vt] = ch;
//        para(i, 0, 26, mask);
        l = lower_bound(rating, rating + lfCnt, pos[vt]) - rating;
        r = upper_bound(rating, rating + lfCnt, pos[vt] + sbtr[vt] - 1) - rating; r--;
//        pii(l, r); nl;
        update(0, n - 1, 0, l, r, mask); mem(mask, 0);
        for(j = 0, sm = 0; j < 26; j++){ sm += tree[0][j]; }
//        para(j, 0, 26, tree[0]);
        if(ht[ara[0]] - sm < 0){ ps("Fou\n"); }
        else{
//            pi(ht[ara[0]] - sm); nl;
            for(j = 0, ret = 0; j < 26; j++){
                ret += (j + 1) * (ht[ara[0]] - sm + tree[0][j]);
            }
            ps("Shi "); pi(ret); nl;
        }
    }
}
int main(){
//    freopen("input.txt","r",stdin);
//    freopen("output.txt", "w", stdout);
    input();
    solve();
}


#include<stdio.h>
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<string.h>

#ifdef LOCAL
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#else
#define NDEBUG
#define eprintf(...) do {} while (0)
#endif
#include<cassert>

using namespace std;

typedef long long LL;
typedef vector<int> VI;

#define REP(i,n) for(int i=0, i##_len=(n); i<i##_len; ++i)
#define EACH(i,c) for(__typeof((c).begin()) i=(c).begin(),i##_end=(c).end();i!=i##_end;++i)

template<class T> inline void amin(T &x, const T &y) { if (y<x) x=y; }
template<class T> inline void amax(T &x, const T &y) { if (x<y) x=y; }
template<class Iter> void rprintf(const char *fmt, Iter begin, Iter end) {
    for (bool sp=0; begin!=end; ++begin) { if (sp) putchar(' '); else sp = true; printf(fmt, *begin); }
    putchar('\n');
}
struct Seg {
    bool valid;
    int C[27];
    int U[27];

    Seg() {
	valid = true;
	memset(C, 0, sizeof C);
	memset(U, 0, sizeof U);
    }
    void add(char c, int v) {
	if (c == '?') C[26] += v;
	else C[c-'a'] += v;
    }

    void fresh(const Seg &a, const Seg &b) {
	valid = false;
	if (a.valid && b.valid) {
	    valid = true;
	    int qa = a.U[26];
	    int qb = b.U[26];
	    REP (c, 26) {
		U[c] = C[c];
		if (a.U[c] > b.U[c]) {
		    qb -= a.U[c] - b.U[c];
		    U[c] += a.U[c];
		} else {
		    qa -= b.U[c] - a.U[c];
		    U[c] += b.U[c];
		}
	    }
	    if (qa < 0 || qb < 0) {
		valid = false;
	    } else {
		assert(qa == qb);
		U[26] = C[26] + qa;
	    }
	}
    }

    void fresh() {
	valid = true;
	REP (i, 27) U[i] = C[i];
    }
};

const int MAXN = 150011;
int N, Q;
char S[MAXN];
int par[MAXN];
VI G[MAXN];

int depth[MAXN];
int head[MAXN];
int tail[MAXN];
Seg seg[MAXN];

void MAIN() {
    scanf("%d%d", &N, &Q);
    REP (i, N-1) {
	int v = i+1;
	int p;
	scanf("%d%s", &p, S+v);
	p--;
	G[p].push_back(v);
	par[v] = p;
    }

    REP (i, N) {
	EACH (e, G[i]) depth[*e] = depth[i]+1;
    }
    int ma = *max_element(depth, depth+N);
    bool yes = true;
    REP (i, N) if (G[i].empty() && depth[i] != ma) {
	yes = false;
	break;
    }
    if (yes) {
	REP (i, N) {
	    EACH (e, G[i]) {
		if (G[i].size() == 2u) {
//		    skip[*e] = i;
		    head[*e] = *e;
		} else {
//		    skip[*e] = skip[i];
		    head[*e] = head[i];
		}
	    }
	}
	for (int i=N; i--;) {
	    if (G[i].size() == 1u) {
		tail[i] = tail[G[i][0]];
	    } else {
		tail[i] = i;
	    }
	}

	for (int i=N; i--;) {
	    int h = head[i];
	    if (i) {
		seg[h].add(S[i], 1);
	    }
	    if (h == i && G[tail[h]].size() == 2u) {
		int a = G[tail[h]][0];
		int b = G[tail[h]][1];
		seg[h].fresh(seg[a], seg[b]);
	    } else {
		seg[h].fresh();
	    }
	}
    }

    REP ($, Q) {
	int v;
	static char s[11];
	scanf("%d%s", &v, s);
	v--;
	if (S[v] != s[0]) {
	    int h = head[v];
	    seg[h].add(S[v], -1);
	    seg[h].add(s[0], 1);
	    S[v] = s[0];
	    while (1) {
		if (G[tail[h]].size() == 2u) {
		    int a = G[tail[h]][0];
		    int b = G[tail[h]][1];
		    seg[h].fresh(seg[a], seg[b]);
		} else {
		    seg[h].fresh();
		}
		if (h == 0) break;
		else h = head[par[h]];
	    }
	}

	if (seg[0].valid) {
	    LL ans = 0;
	    REP (c, 26) ans += (c+1LL) * (seg[0].U[c] + seg[0].U[26]);
	    printf("Shi %lld\n", ans);
	} else {
	    puts("Fou");
	}
    }
}

int main() {
    int TC = 1;
//    scanf("%d", &TC);
    REP (tc, TC) MAIN();
    return 0;
}


#include<stdio.h>
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<string.h>

#ifdef LOCAL
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#else
#define NDEBUG
#define eprintf(...) do {} while (0)
#endif
#include<cassert>

using namespace std;

typedef long long LL;
typedef vector<int> VI;

#define REP(i,n) for(int i=0, i##_len=(n); i<i##_len; ++i)
#define EACH(i,c) for(__typeof((c).begin()) i=(c).begin(),i##_end=(c).end();i!=i##_end;++i)

template<class T> inline void amin(T &x, const T &y) { if (y<x) x=y; }
template<class T> inline void amax(T &x, const T &y) { if (x<y) x=y; }
template<class Iter> void rprintf(const char *fmt, Iter begin, Iter end) {
    for (bool sp=0; begin!=end; ++begin) { if (sp) putchar(' '); else sp = true; printf(fmt, *begin); }
    putchar('\n');
}
struct Seg {
    bool valid;
    int C[27];
    int U[27];

    Seg() {
	valid = true;
	memset(C, 0, sizeof C);
	memset(U, 0, sizeof U);
    }
    void add(char c, int v) {
	if (c == '?') C[26] += v;
	else C[c-'a'] += v;
    }

    void fresh(const Seg &a, const Seg &b) {
	valid = false;
	if (a.valid && b.valid) {
	    valid = true;
	    int qa = a.U[26];
	    int qb = b.U[26];
	    REP (c, 26) {
		U[c] = C[c];
		if (a.U[c] > b.U[c]) {
		    qb -= a.U[c] - b.U[c];
		    U[c] += a.U[c];
		} else {
		    qa -= b.U[c] - a.U[c];
		    U[c] += b.U[c];
		}
	    }
	    if (qa < 0 || qb < 0) {
		valid = false;
	    } else {
		assert(qa == qb);
		U[26] = C[26] + qa;
	    }
	}
    }

    void fresh() {
	valid = true;
	REP (i, 27) U[i] = C[i];
    }
};

const int MAXN = 150011;
int N, Q;
char S[MAXN];
int par[MAXN];
VI G[MAXN];

int depth[MAXN];
int head[MAXN];
int tail[MAXN];
Seg seg[MAXN];

void MAIN() {
    scanf("%d%d", &N, &Q);
    REP (i, N-1) {
	int v = i+1;
	int p;
	scanf("%d%s", &p, S+v);
	p--;
	G[p].push_back(v);
	par[v] = p;
    }

    REP (i, N) {
	EACH (e, G[i]) depth[*e] = depth[i]+1;
    }
    int ma = *max_element(depth, depth+N);
    bool yes = true;
    REP (i, N) if (G[i].empty() && depth[i] != ma) {
	yes = false;
	break;
    }
    if (yes) {
	REP (i, N) {
	    EACH (e, G[i]) {
		if (G[i].size() == 2u) {
		    head[*e] = *e;
		} else {
		    head[*e] = head[i];
		}
	    }
	}
	for (int i=N; i--;) {
	    if (G[i].size() == 1u) {
		tail[i] = tail[G[i][0]];
	    } else {
		tail[i] = i;
	    }
	}

	for (int i=N; i--;) {
	    int h = head[i];
	    if (i) {
		seg[h].add(S[i], 1);
	    }
	    if (h == i && G[tail[h]].size() == 2u) {
		int a = G[tail[h]][0];
		int b = G[tail[h]][1];
		seg[h].fresh(seg[a], seg[b]);
	    } else {
		seg[h].fresh();
	    }
	}
    }

    REP ($, Q) {
	int v;
	static char s[11];
	scanf("%d%s", &v, s);
	v--;
	if (yes && S[v] != s[0]) {
	    int h = head[v];
	    seg[h].add(S[v], -1);
	    seg[h].add(s[0], 1);
	    S[v] = s[0];
	    while (1) {
		if (G[tail[h]].size() == 2u) {
		    int a = G[tail[h]][0];
		    int b = G[tail[h]][1];
		    seg[h].fresh(seg[a], seg[b]);
		} else {
		    seg[h].fresh();
		}
		if (h == 0) break;
		else h = head[par[h]];
	    }
	}

	if (yes && seg[0].valid) {
	    LL ans = 0;
	    REP (c, 26) ans += (c+1LL) * (seg[0].U[c] + seg[0].U[26]);
	    printf("Shi %lld\n", ans);
	} else {
	    puts("Fou");
	}
    }
}

int main() {
    int TC = 1;
//    scanf("%d", &TC);
    REP (tc, TC) MAIN();
    return 0;
}


#include <bits/stdc++.h>
#define all(x) x.begin(), x.end()
#define long long long
using namespace std;

const int N = 3e5;
int n, q;
int deg[N];			// unmerged degree
int dep[N];			// unmerged depth
int len[N];			// unmerged subtree height
int p[N];			// unmerged	ancestor
char c[N];			// unmerged	edge char
int dn[N];			// merged 	component
int up[N];			// merged 	ancestor
int dp[N][26];		// merged 	subtree anagramm
int cn[N][26];		// merged 	counters of edge
vector<int> small;	// merged 	vertexes

int query() {
	//cerr << "!!!!!" << endl;
	//for (int i = 0; i < n; ++i) {
	//	for (int j = 0; j < 2; ++j) {
	//		cerr << cn[i][j] << " ";
	//	}
	//	cerr << endl;
	//}
	fill_n(dp[0], 26, 0);
	for (int v : small) {
		fill_n(dp[v], 26, 0);
	}
	for (int v : small) {
		assert(v);
		int sum = accumulate(dp[v], dp[v] + 26, 0);
		if (sum > len[v]) {
			return -1;
		}
		for (int i = 0; i < 26; ++i) {
			dp[v][i] += cn[v][i];
		}
		int pr = up[v];
		for (int i = 0; i < 26; ++i) {
			dp[pr][i] = max(dp[pr][i], dp[v][i]);
		}
	}
	int sum = accumulate(dp[0], dp[0] + 26, 0);
	if (sum > len[0]) {
		return -1;
	}
	int add = len[0] - sum;
	//cerr << "------" << endl;
	//cerr << "add = " << add << endl;
	int res = 0;
	for (int i = 0; i < 26; ++i) {
		int mx = dp[0][i] + add;
		//cerr << mx << " ";
		res += (i + 1) * mx;
	}
	//cerr << endl;
	return res;
}

void update(int v, char newc) {
	char oldc = c[v];
	c[v] = newc;
	v = dn[v];
	if (oldc != '?') {
		--cn[v][oldc - 'a'];
	}
	if (newc != '?') {
		++cn[v][newc - 'a'];
	}
}

void no() {
	for (int i = 0; i < q; ++i) {
		cout << "Fou\n";
	}
	exit(0);
}

int main() {
#ifdef LC
	assert(freopen("input.txt", "r", stdin));
#else
#endif
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> q;
	c[0] = '?';
	p[0] = -1;
	for (int i = 1; i < n; ++i) {
		cin >> p[i] >> c[i];
		--p[i];
		++deg[p[i]];
		dep[i] = dep[p[i]] + 1;
	}

	for (int i = n - 1; i > 0; --i) {
		int pr = p[i];
		len[pr] = len[i] + 1;
		if (deg[i] != 1) {
			small.push_back(i);
			dn[i] = i;
		}
		if (deg[pr] == 1) {
			dn[pr] = dn[i];
		}
	}
	for (int i = 0; i < n; ++i) {
		if (!deg[i] && dep[i] != len[0]) {
			cerr << i + 1 << " " << dep[i] << " " << len[0] << endl;
			no();
		}
	}
	up[0] = 0;
	for (int i = 1; i < n; ++i) {
		int pr = p[i];
		if (deg[pr] == 1) {
			up[i] = up[pr];
			copy_n(cn[pr], 26, cn[i]);
		} else {
			up[i] = pr;

		}
		if (c[i] != '?') {
			++cn[i][c[i] - 'a'];
		}
	}

	while (q--) {
		int v;
		char newc;
		cin >> v >> newc;
		update(v - 1, newc);
		int res = query();
		if (res == -1) {
			cout << "Fou\n";
		} else {
			cout << "Shi " << res << "\n";
		}
	}

	return 0;
}


#include <bits/stdc++.h>
#define all(x) x.begin(), x.end()
#define long long long
using namespace std;

const int N = 3e5;
int n, q;
vector<int> g[N];	// unmerged tree
int deg[N];			// unmerged degree
int dep[N];			// unmerged depth
int len[N];			// unmerged subtree height
int p[N];			// unmerged	ancestor
char c[N];			// unmerged	edge char
int dn[N];			// merged 	component
int up[N];			// merged 	ancestor
int dp[N][26];		// merged 	subtree anagramm
int cn[N][26];		// merged 	counters of edge
vector<int> small;	// merged 	vertexes
int badcnt = 0;

int update(int v, char newc) {
	char oldc = c[v];
	c[v] = newc;
	v = dn[v];
	if (oldc != '?') {
		--cn[v][oldc - 'a'];
	}
	if (newc != '?') {
		++cn[v][newc - 'a'];
	}
	v = up[v];
	while (v != 0) {
		int sum;
		sum = accumulate(dp[v], dp[v] + 26, 0);
		if (sum > len[v]) {
			--badcnt;
		}

		fill_n(dp[v], 26, 0);
		for (int u : g[v]) {
			for (int i = 0; i < 26; ++i) {
				dp[v][i] = max(dp[v][i], dp[u][i] + cn[u][i]);
			}
		}

		sum = accumulate(dp[v], dp[v] + 26, 0);
		if (sum > len[v]) {
			++badcnt;
		}
		v = up[v];
	}
	fill_n(dp[0], 26, 0);
	for (int u : g[0]) {
		for (int i = 0; i < 26; ++i) {
			dp[0][i] = max(dp[0][i], dp[u][i] + cn[u][i]);
		}
	}
	if (badcnt > 0) {
		return -1;
	}
	int sum = accumulate(dp[0], dp[0] + 26, 0);
	int add = len[0] - sum;
	if (add < 0) {
		return -1;
	}
	int res = 0;
	for (int i = 0; i < 26; ++i) {
		int mx = dp[0][i] + add;
		res += (i + 1) * mx;
	}
	return res;
}

void no() {
	for (int i = 0; i < q; ++i) {
		cout << "Fou\n";
	}
	exit(0);
}

int main() {
#ifdef LC
	assert(freopen("input.txt", "r", stdin));
#else
#endif
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> q;
	c[0] = '?';
	p[0] = -1;
	for (int i = 1; i < n; ++i) {
		cin >> p[i] >> c[i];
		--p[i];
		++deg[p[i]];
		dep[i] = dep[p[i]] + 1;
	}

	for (int i = n - 1; i > 0; --i) {
		int pr = p[i];
		len[pr] = len[i] + 1;
		if (deg[i] != 1) {
			dn[i] = i;
		}
		if (deg[pr] == 1) {
			dn[pr] = dn[i];
		}
	}
	for (int i = 0; i < n; ++i) {
		if (!deg[i] && dep[i] != len[0]) {
			no();
		}
	}
	up[0] = 0;
	for (int i = 1; i < n; ++i) {
		int pr = p[i];
		if (deg[pr] == 1) {
			up[i] = up[pr];
			copy_n(cn[pr], 26, cn[i]);
		} else {
			up[i] = pr;
		}
		if (c[i] != '?') {
			++cn[i][c[i] - 'a'];
		}
	}
	for (int v = n - 1; v > 0; --v) {
		if (deg[v] == 1) {
			continue;
		}
		g[up[v]].push_back(v);
		int sum = accumulate(dp[v], dp[v] + 26, 0);
		if (sum > len[v]) {
			++badcnt;
		}
		int pr = up[v];
		for (int i = 0; i < 26; ++i) {
			dp[pr][i] = max(dp[pr][i], dp[v][i] + cn[v][i]);
		}
	}

	while (q--) {
		int v;
		char newc;
		cin >> v >> newc;
		int res = update(v - 1, newc);
		if (res == -1) {
			cout << "Fou\n";
		} else {
			cout << "Shi " << res << "\n";
		}
	}

	return 0;
}


#include <bits/stdc++.h>
#define all(x) x.begin(), x.end()
#define long long long
using namespace std;

const int N = 3e5;
int n, q;
int deg[N];			// unmerged degree
int dep[N];			// unmerged depth
int len[N];			// unmerged subtree height
int p[N];			// unmerged	ancestor
char c[N];			// unmerged	edge char
int dn[N];			// merged 	component
int up[N];			// merged 	ancestor
int dp[N][26];		// merged 	subtree anagramm
int cn[N][26];		// merged 	counters of edge
vector<int> small;	// merged 	vertexes

int query() {
	//cerr << "!!!!!" << endl;
	//for (int i = 0; i < n; ++i) {
	//	for (int j = 0; j < 2; ++j) {
	//		cerr << cn[i][j] << " ";
	//	}
	//	cerr << endl;
	//}
	fill_n(dp[0], 26, 0);
	for (int v : small) {
		fill_n(dp[v], 26, 0);
	}
	for (int v : small) {
		assert(v);
		int sum = accumulate(dp[v], dp[v] + 26, 0);
		if (sum > len[v]) {
			return -1;
		}
		for (int i = 0; i < 26; ++i) {
			dp[v][i] += cn[v][i];
		}
		int pr = up[v];
		for (int i = 0; i < 26; ++i) {
			dp[pr][i] = max(dp[pr][i], dp[v][i]);
		}
	}
	int sum = accumulate(dp[0], dp[0] + 26, 0);
	if (sum > len[0]) {
		return -1;
	}
	int add = len[0] - sum;
	//cerr << "------" << endl;
	//cerr << "add = " << add << endl;
	int res = 0;
	for (int i = 0; i < 26; ++i) {
		int mx = dp[0][i] + add;
		//cerr << mx << " ";
		res += (i + 1) * mx;
	}
	//cerr << endl;
	return res;
}

void update(int v, char newc) {
	char oldc = c[v];
	c[v] = newc;
	v = dn[v];
	if (oldc != '?') {
		--cn[v][oldc - 'a'];
	}
	if (newc != '?') {
		++cn[v][newc - 'a'];
	}
}

void no() {
	for (int i = 0; i < q; ++i) {
		cout << "Fou\n";
	}
	exit(0);
}

int main() {
#ifdef LC
	assert(freopen("input.txt", "r", stdin));
#else
#endif
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> q;
	c[0] = '?';
	p[0] = -1;
	for (int i = 1; i < n; ++i) {
		cin >> p[i] >> c[i];
		--p[i];
		++deg[p[i]];
		dep[i] = dep[p[i]] + 1;
	}

	for (int i = n - 1; i > 0; --i) {
		int pr = p[i];
		len[pr] = len[i] + 1;
		if (deg[i] != 1) {
			small.push_back(i);
			dn[i] = i;
		}
		if (deg[pr] == 1) {
			dn[pr] = dn[i];
		}
	}
	for (int i = 0; i < n; ++i) {
		if (!deg[i] && dep[i] != len[0]) {
			//cerr << i + 1 << " " << dep[i] << " " << len[0] << endl;
			no();
		}
	}
	assert((int)small.size() < 1000);
	up[0] = 0;
	for (int i = 1; i < n; ++i) {
		int pr = p[i];
		if (deg[pr] == 1) {
			up[i] = up[pr];
			copy_n(cn[pr], 26, cn[i]);
		} else {
			up[i] = pr;
		}
		if (c[i] != '?') {
			++cn[i][c[i] - 'a'];
		}
	}

	while (q--) {
		int v;
		char newc;
		cin >> v >> newc;
		update(v - 1, newc);
		int res = query();
		if (res == -1) {
			cout << "Fou\n";
		} else {
			cout << "Shi " << res << "\n";
		}
	}

	return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
#define mp make_pair
#define PI pair<int,int>
#define For(i,l,r) for(int i=(int)(l);i<=(int)(r);i++)
#define Rep(i,r,l) for(int i=(int)(r);i>=(int)(l);i--)
#define pb push_back
#define fi first
#define se second
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline ll read(){
	ll x = 0; char ch = gc(); bool positive = 1;
	for (; !isdigit(ch); ch = gc())	if (ch == '-')	positive = 0;
	for (; isdigit(ch); ch = gc())	x = x * 10 + ch - '0';
	return positive ? x : -x;
}
inline void write(ll a){
    if(a<0){
    	a=-a; putchar('-');
	}
    if(a>=10)write(a/10);
    putchar('0'+a%10);
}
inline void writeln(ll a){write(a); puts("");}
inline void wri(ll a){write(a); putchar(' ');}
inline ull rnd(){
	return ((ull)rand()<<30^rand())<<4|rand()%4;
}
const int N=150005,K=26;
vector<int> v[N];
int zs[N],fa[N],lst[N],dep[N],cnt,mxdep;
char ch[N];
void in(int nod,int x){
	if(x==1){
		if(++zs[nod]==mxdep-dep[nod]+1)cnt++;
	}else{
		if(--zs[nod]==mxdep-dep[nod])cnt--;
	}
}
struct data{
	int mx[N],s[N];
	bool push_up(int nod){
		if(mx[nod]!=max(mx[v[nod][0]],mx[v[nod][1]])+s[nod]){
			mx[nod]=max(mx[v[nod][0]],mx[v[nod][1]])+s[nod]; return 1;
		}else return 0;
	}
	void ins(int pos,int de){
		mx[pos]+=de; s[pos]+=de;
		while(pos>1){
			if(v[fa[pos]].size()==2){if(!push_up(fa[pos]))return; in(fa[pos],de);}
			else mx[lst[fa[pos]]]+=de; pos=lst[fa[pos]];
		}
	}
}T[K];
void dfs(int p){
	if(v[p].size()==2)lst[p]=p;
	else lst[p]=v[fa[p]].size()!=1?p:lst[fa[p]];
	for(auto i:v[p]){dep[i]=dep[p]+1; dfs(i);}
}
int main(){
	int n=read(),q=read(); mxdep=0;
	For(i,2,n){v[fa[i]=read()].pb(i); ch[i]=getchar();}
	dfs(1);
	For(i,2,n)if(v[i].size()==0){
		if(!mxdep)mxdep=dep[i];
		else if(dep[i]!=mxdep){
			while(q--)puts("Fou"); return 0;
		}
	}
	For(i,2,n)if(ch[i]!='?')T[ch[i]-'a'].ins(lst[i],1);
	while(q--){
		int pos=read(),sum=mxdep,ans=0;
		if(ch[pos]!='?')T[ch[pos]-'a'].ins(lst[pos],-1);
		ch[pos]=getchar();
		if(ch[pos]!='?')T[ch[pos]-'a'].ins(lst[pos],1);
		if(cnt){puts("Fou"); continue;}
		For(i,0,25)sum-=T[i].mx[1]; //cout<<mxdep<<" "<<sum<<" fjzz"<<endl;
		For(i,0,25)ans+=(sum+T[i].mx[1])*(i+1);
		printf("Shi "); writeln(ans);
	}
}


//Zory-2019
#include<bits/stdc++.h>
using namespace std;
namespace mine
{
    typedef long long ll;
    #define pr pair<int,int>
    #define FR first
    #define SE second
    #define MP make_pair
    #define PB push_back
    #define vc vector
    #define all(x) (x).begin(),(x).end()
    #define sz(x) ((int)(x).size())
    #define bin(x) (1ll<<(x))
    #define GG(x) if(x) {puts("error");exit(666);}
    #define fo(i,l,r) for(int i=(l),I=(r);i<=I;i++)
    #define fd(i,r,l) for(int i=(r),I=(l);i>=I;i--)
    ll qread()
    {
        ll ans=0,f=1;char c=getchar();
        while(c<'0' or c>'9') {if(c=='-')f=-1;c=getchar();}
        while('0'<=c and c<='9') ans=ans*10+c-'0',c=getchar();
        return ans*f;
    }
    void write(ll num)
    {
        if(num<0) putchar('-'),num=-num;
        if(num>=10) write(num/10);
        putchar('0'+num%10);
    }
    void write1(ll num){write(num);putchar(' ');}
    void write2(ll num){write(num);putchar('\n');}
    template<typename T> void chmax(T &x,const T y) {x=(x>y?x:y);}
    template<typename T> void chmin(T &x,const T y) {x=(x<y?x:y);}
    ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}

    const int INF=0x3f3f3f3f;
    const int MOD=1e9+7;
    int mm(const int x){return x>=MOD?x-MOD:x;}
    template<typename T> void add(T &x,const int &y){x=(x+y>=MOD?x+y-MOD:x+y);}
    ll qpower(ll x,ll e,int mod=MOD){ll ans=1;GG(e<0)while(e){if(e&1)ans=ans*x%mod;x=x*x%mod;e>>=1;}return ans;}
    ll invm(ll x){return qpower(x,MOD-2);}
    const int N=2e5+10;

    int fa[N],len[N];
    vc<int> son[N];int ss[N];//son
    int err=0;//有冲突的点数
    int f[N][30],sum[N];//统计每种颜色的最大长度
    int cnt[N][30];//颜色当前系数
    void update(int c,int x,int val)
    {
        cnt[x][c]+=val;
        while(fa[x])
        {
            x=fa[x];err-=(sum[x]>len[x]);sum[x]=0;
            fo(i,0,25)
            {
                f[x][i]=0;
                for(auto y:son[x]) chmax(f[x][i],f[y][i]+cnt[y][i]);
                sum[x]+=f[x][i];
            }
            err+=(sum[x]>len[x]);
        }
    }
    //顶部作为编号代表，但其实真正的点是最底下的点
    int top[N];int findfa(int x){return top[x]==x?x:top[x]=findfa(top[x]);}
    char col[N][10];//边的颜色
    void main()
	{
        int n=qread(),q=qread();top[1]=1;
        fo(x,2,n) fa[x]=qread(),ss[fa[x]]++,top[x]=x,scanf("%s",col[x]);
        bool gg=0;
        fd(x,n,2)
        {
            chmax(len[fa[x]],len[x]+1);if(len[fa[x]]!=len[x]+1) gg=1;
            if(ss[fa[x]]==1) top[x]=findfa(fa[x]);
        }
        if(gg){while(q--)puts("Fou");return;}
        fo(x,1,n) if(findfa(x)==x) fa[x]=findfa(fa[x]),son[fa[x]].PB(x);
        int mxdep=len[1];
        fo(x,1,n) chmin(len[findfa(x)],len[x]),update(col[x][0]-'a',findfa(x),1);
        while(q--)
        {
            int x=qread();update(col[x][0]-'a',findfa(x),-1);
            scanf("%s",col[x]);update(col[x][0]-'a',findfa(x),1);
            if(err) puts("Fou");
            else
            {
                printf("Shi ");
                int ans=0;fo(i,0,25) ans+=(i+1)*(f[1][i]+mxdep-sum[1]);write2(ans);
            }
        }
	}
};//(ans+MOD)%MOD
signed main()
{
    // freopen("a.in","r",stdin);
    srand(time(0));
    mine::main();
}


//Zory-2019
#include<bits/stdc++.h>
using namespace std;
namespace mine
{
    typedef long long ll;
    #define pr pair<int,int>
    #define FR first
    #define SE second
    #define MP make_pair
    #define PB push_back
    #define vc vector
    #define all(x) (x).begin(),(x).end()
    #define sz(x) ((int)(x).size())
    #define bin(x) (1ll<<(x))
    #define GG(x) if(x) {puts("error");exit(666);}
    #define fo(i,l,r) for(int i=(l),I=(r);i<=I;i++)
    #define fd(i,r,l) for(int i=(r),I=(l);i>=I;i--)
    ll qread()
    {
        ll ans=0,f=1;char c=getchar();
        while(c<'0' or c>'9') {if(c=='-')f=-1;c=getchar();}
        while('0'<=c and c<='9') ans=ans*10+c-'0',c=getchar();
        return ans*f;
    }
    void write(ll num)
    {
        if(num<0) putchar('-'),num=-num;
        if(num>=10) write(num/10);
        putchar('0'+num%10);
    }
    void write1(ll num){write(num);putchar(' ');}
    void write2(ll num){write(num);putchar('\n');}
    template<typename T> void chmax(T &x,const T y) {x=(x>y?x:y);}
    template<typename T> void chmin(T &x,const T y) {x=(x<y?x:y);}
    ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}

    const int INF=0x3f3f3f3f;
    const int MOD=1e9+7;
    int mm(const int x){return x>=MOD?x-MOD:x;}
    template<typename T> void add(T &x,const int &y){x=(x+y>=MOD?x+y-MOD:x+y);}
    ll qpower(ll x,ll e,int mod=MOD){ll ans=1;GG(e<0)while(e){if(e&1)ans=ans*x%mod;x=x*x%mod;e>>=1;}return ans;}
    ll invm(ll x){return qpower(x,MOD-2);}
    const int N=2e5+10;

    int fa[N],len[N];
    vc<int> son[N];int ss[N];//son
    int err=0;//有冲突的点数
    int f[N][30],sum[N];//统计每种颜色的最大长度
    int cnt[N][30];//颜色当前系数
    void update(int c,int x,int val)
    {
        if(c=='?'-'a') return;
        cnt[x][c]+=val;
        while(fa[x])
        {
            x=fa[x];err-=(sum[x]>len[x]);sum[x]-=f[x][c];f[x][c]=0;
            for(auto y:son[x]) chmax(f[x][c],f[y][c]+cnt[y][c]);
            sum[x]+=f[x][c];
            err+=(sum[x]>len[x]);
        }
    }
    //顶部作为编号代表，但其实真正的点是最底下的点
    int top[N];int findfa(int x){return top[x]==x?x:top[x]=findfa(top[x]);}
    char col[N][10];//边的颜色
    void main()
	{
        int n=qread(),q=qread();top[1]=1;
        fo(x,2,n) fa[x]=qread(),ss[fa[x]]++,top[x]=x,scanf("%s",col[x]);
        bool gg=0;
        fd(x,n,2)
        {
            chmax(len[fa[x]],len[x]+1);if(len[fa[x]]!=len[x]+1) gg=1;
            if(ss[fa[x]]==1) top[x]=fa[x];
        }
        if(gg){while(q--)puts("Fou");return;}
        fo(x,1,n) if(findfa(x)==x) fa[x]=findfa(fa[x]),son[fa[x]].PB(x);
        int mxdep=len[1];
        fo(x,2,n) chmin(len[findfa(x)],len[x]),update(col[x][0]-'a',findfa(x),1);
        while(q--)
        {
            int x=qread();update(col[x][0]-'a',findfa(x),-1);
            scanf("%s",col[x]);update(col[x][0]-'a',findfa(x),1);
            if(err) puts("Fou");
            else
            {
                printf("Shi ");int sm=0;fo(i,0,25) sm+=cnt[1][i];
                int ans=0;fo(i,0,25) ans+=(i+1)*(f[1][i]+cnt[1][i]+mxdep-(sum[1]+sm));write2(ans);
            }
        }
	}
};//(ans+MOD)%MOD
signed main()
{
    // freopen("a.in","r",stdin);
    srand(time(0));
    mine::main();
}


#include<bits/stdc++.h>
#define maxc 27
#define maxn 150050
using namespace std;
typedef long long LL;

int n,m;

int up[maxn];
char s[10];

int fa[maxn];
int dep[maxn],D;
vector<int> G[maxn];

bool fake[maxn];
int sum[maxn],len[maxn];
int dp[maxn][maxc],cnt[maxn][maxc];

int chr(int i)	{
	return i=='?'?26:i-'a';
}

void init()	{
	scanf("%d%d",&n,&m);
	for (int i=2;i<=n;++i)	{
		scanf("%d%s",fa+i,s);
		up[i]=chr(*s);
		G[fa[i]].push_back(i);
		dep[i]=dep[fa[i]]+1;
	}
}

int tp[maxn];

bool judge()	{
	D=-1;
	for (int i=1;i<=n;++i)	{
		if (G[i].size())	continue;
		if (~D&&dep[i]!=D)	return 0;
		D=dep[i];
	}
	return 1;
}

void modify(int i,int c,int d)	{
	if (c==26)	return ;
	cnt[i=tp[i]][c]+=d;
	for (i=tp[fa[i]];i;i=tp[fa[i]])	{
		assert(G[i].size()==2);
		int ls=G[i][0],rs=G[i][1];
		sum[i]-=dp[i][c];
		dp[i][c]=max(dp[ls][c]+cnt[ls][c],dp[rs][c]+cnt[rs][c]);
		sum[i]+=dp[i][c];
		fake[i]=fake[ls]|fake[rs]|(sum[i]>D-dep[i]);
	}
}

void solve()	{
	tp[1]=1;
	for (int i=2;i<=n;++i)	{
		if (G[fa[i]].size()==1)
			tp[i]=tp[fa[i]],++len[tp[i]],dep[tp[i]]=dep[i];
		else
			tp[i]=i;
//		cout<<i<<" "<<tp[i]<<endl;
	}
	for (int i=1;i<=n;++i)	G[i].clear();
	for (int i=2;i<=n;++i)
		if (tp[i]==i)
			G[tp[fa[i]]].push_back(i);

	for (int i=2;i<=n;++i)	modify(i,up[i],1);

	while (m--)	{
//		cout<<"----------------"<<endl;

		int i;
		scanf("%d%s",&i,s);

		modify(i,up[i],-1);
		modify(i,up[i]=chr(*s),1);

		/*for (int i=1;i<=n;++i)
			if (i==tp[i])	{
				cout<<i<<"("<<sum[i]<<","<<dep[i]<<"):";
				for (int c=0;c<maxc;++c)
					cout<<dp[i][c]<<" ";
				cout<<endl;
			}*/

		if (fake[1])
			puts("Fou");
		else	{
			LL ans=0,s=D-sum[1];
			for (int c=0;c<26;++c)
				s-=cnt[1][c];
			for (int c=0;c<26;++c)
				ans+=(s+dp[1][c]+cnt[1][c])*(c+1);
			printf("Shi %lld\n",ans);
		}
	}
}

int main()	{
	init();
	if (!judge())
		while (m--)	puts("Fou");
	else
		solve();
	return 0;
}