// 演算法：線段樹，節點記錄最長同字元段與前綴/後綴，合併時處理跨界段。
// Algorithm: segment tree; each node stores the best run plus prefix/suffix so a
// run crossing the split of two children is merged correctly.

class Solution {
    // 每個節點的資訊打包成一個結構 / a struct bundling one node's fields
    struct Node {
        int pref = 0, suf = 0, best = 0, len = 0;  // 前綴/後綴/最佳/長度 / prefix/suffix/best/length
        char lc = 0, rc = 0;                        // 左右端字元 / leftmost & rightmost chars
    };

    vector<Node> tree;   // 用 vector 當線段樹陣列 / a vector as the segment-tree array
    string s;            // 目前的字串狀態 / the current string state

    // 合併左右兩個子節點 / merge two child nodes into their parent
    Node merge(const Node& a, const Node& b) {
        // 若某一子是空段(len==0)，直接回傳另一子 / if a child is empty, return the other
        if (a.len == 0) return b;
        if (b.len == 0) return a;

        Node r;
        r.len = a.len + b.len;               // 長度相加 / lengths add up
        r.lc = a.lc;                         // 左端來自左子 / left end from left child
        r.rc = b.rc;                         // 右端來自右子 / right end from right child

        r.pref = a.pref;                     // 前綴預設是左子前綴 / prefix defaults to left child's
        if (a.pref == a.len && a.rc == b.lc) // 左子整段同字元且邊界相接 / left child all one char and boundary matches
            r.pref = a.len + b.pref;         // 前綴延伸進右子 / extend into right child

        r.suf = b.suf;                       // 後綴預設是右子後綴 / suffix defaults to right child's
        if (b.suf == b.len && b.lc == a.rc)  // 右子整段同字元且邊界相接 / right child all one char and boundary matches
            r.suf = b.len + a.suf;           // 後綴延伸進左子 / extend into left child

        r.best = max(a.best, b.best);        // 先取兩子最佳 / max of children's best
        if (a.rc == b.lc)                    // 邊界字元相同才有跨界段 / crossing run only if boundary chars match
            r.best = max(r.best, a.suf + b.pref);  // 跨界段 = 左後綴 + 右前綴 / crossing = left suffix + right prefix
        return r;
    }

    // 建樹 / build the tree over range [l, r] at array index node
    void build(int node, int l, int r) {
        if (l == r) {                        // 葉子節點 / leaf node
            tree[node] = {1, 1, 1, 1, s[l], s[l]};  // 單字元：各值為 1，兩端同字元 / single char: all 1s, both ends = s[l]
            return;
        }
        int mid = (l + r) / 2;               // 中點 / midpoint
        build(2 * node,     l,     mid);     // 建左半 / build left half
        build(2 * node + 1, mid + 1, r);     // 建右半 / build right half
        tree[node] = merge(tree[2 * node], tree[2 * node + 1]);  // 合併 / merge children
    }

    // 單點更新：把 pos 的字元設為 c / point update: set char at pos to c
    void update(int node, int l, int r, int pos, char c) {
        if (l == r) {                        // 目標葉子 / target leaf
            tree[node].lc = tree[node].rc = c;  // 改字元；其餘欄位仍為 1 / change char; other fields stay 1
            return;
        }
        int mid = (l + r) / 2;
        if (pos <= mid) update(2 * node,     l,     mid, pos, c);  // 往左找 / recurse left
        else            update(2 * node + 1, mid + 1, r, pos, c);  // 往右找 / recurse right
        tree[node] = merge(tree[2 * node], tree[2 * node + 1]);    // 重新合併 / recombine
    }

public:
    vector<int> longestRepeating(string s, string queryCharacters, vector<int>& queryIndices) {
        this->s = s;                         // 保存字串到成員 / store the string in the member
        int n = s.size();                    // 字串長度 / string length
        tree.assign(4 * n, Node{});          // 配置 4n 個節點（預設空節點）/ allocate 4n nodes (default-empty)
        build(1, 0, n - 1);                  // 從根(下標1)建樹 / build from root (index 1)

        vector<int> ans;                     // 答案陣列 / the answer array
        ans.reserve(queryIndices.size());    // 預留空間避免多次擴容 / reserve to avoid reallocations
        // range-for：依序取出每個查詢下標 i / range-for over each query index i
        for (int i = 0; i < (int)queryIndices.size(); i++) {
            update(1, 0, n - 1, queryIndices[i], queryCharacters[i]);  // 套用一次修改 / apply one update
            ans.push_back(tree[1].best);     // 根的 best 即答案 / root's best is the answer
        }
        return ans;                          // 回傳結果 / return the results
    }
};
