#include <any>          // 包含any头文件(代码中未实际使用,保留原引入)
#include<bits/stdc++.h> // 包含所有常用标准库头文件
using namespace std;
#define LL long long    // 定义长整型别名,简化代码书写
const LL N = 2e5 + 10;  // 定义常量,最大数据规模(2e5+10)

// 线段树节点结构体,维护区间内各类字符和子序列的数量
struct node {
    LL r;     // 区间内字符'r'的数量
    LL re;    // 区间内子序列"re"的数量
    LL red;   // 区间内子序列"red"的数量
    LL ed;    // 区间内子序列"ed"的数量
    LL d;     // 区间内字符'd'的数量
    LL e;     // 区间内字符'e'的数量
};

string s, t;  // 存储两个输入的字符串
LL n;         // 字符串的长度

// 计算线段树节点p的右儿子下标
LL rs(LL p) {
    return p << 1 | 1;  // 等价于p*2+1
}

// 计算线段树节点p的左儿子下标
LL ls(LL p) {
    return p << 1;      // 等价于p*2
}

// 向上合并线段树节点的信息(由左右儿子更新当前节点)
void push_up(LL p, vector<struct node>& tree) {
    LL l = ls(p), r = rs(p);  // 获取左右儿子的下标
    // 合并单个字符的数量
    tree[p].r = tree[l].r + tree[r].r;
    tree[p].d = tree[l].d + tree[r].d;
    tree[p].e = tree[l].e + tree[r].e;
    // 合并"re"子序列:左区间re + 右区间re + 左区间r数 * 右区间e数
    tree[p].re = tree[l].re + tree[r].re + tree[l].r * tree[r].e;
    // 合并"ed"子序列:左区间ed + 右区间ed + 左区间e数 * 右区间d数
    tree[p].ed = tree[l].ed + tree[r].ed + tree[l].e * tree[r].d;
    // 合并"red"子序列:左区间red + 右区间red + 左区间r数*右区间ed数 + 左区间re数*右区间d数
    tree[p].red = tree[l].red + tree[r].red + tree[l].r * tree[r].ed + tree[l].re * tree[r].d;
}

// 构建线段树
// p:当前线段树节点下标,pl/pr:当前节点维护的区间左右端点,tree:线段树数组,s:待维护的字符串
void build(LL p, LL pl, LL pr, vector<struct node>& tree, string& s) {
    // 递归到叶子节点(区间长度为1)
    if (pl == pr) {
        char c = s[pl - 1];  // 字符串下标从0开始,区间从1开始,需偏移
        // 根据字符类型初始化叶子节点的计数
        if (c == 'r') tree[p].r++;
        else if (c == 'e') tree[p].e++;
        else if (c == 'd') tree[p].d++;
        return;
    }
    // 分治构建左右子树
    LL mid = (pl + pr) >> 1;  // 计算区间中点(等价于(pl+pr)/2)
    build(ls(p), pl, mid, tree, s);        // 构建左子树
    build(rs(p), mid + 1, pr, tree, s);    // 构建右子树
    push_up(p, tree);  // 合并左右子树的信息到当前节点
}

// 更新线段树指定位置的字符
// p:当前线段树节点下标,pl/pr:当前节点维护的区间左右端点,index:要更新的字符串位置,tree:线段树数组,c:新的字符
void update(LL p, LL pl, LL pr, LL index, vector<struct node>& tree, char c) {
    // 递归到叶子节点(找到要更新的位置)
    if (pl == pr) {
        // 重置当前叶子节点的所有计数
        tree[p] = {0, 0, 0, 0, 0, 0};
        // 根据新字符更新计数
        if (c == 'r') tree[p].r++;
        else if (c == 'e') tree[p].e++;
        else if (c == 'd') tree[p].d++;
        return;
    }
    // 分治找到要更新的位置
    LL mid = (pl + pr) >> 1;
    if (index <= mid) update(ls(p), pl, mid, index, tree, c);  // 左子树更新
    else update(rs(p), mid + 1, pr, index, tree, c);           // 右子树更新
    push_up(p, tree);  // 合并更新后的子树信息
}

int main() {
    int q;  // 存储查询操作的数量
    cin >> n >> q;  // 输入字符串长度和查询次数
    cin >> s >> t;  // 输入两个字符串

    // 初始化两个线段树数组,大小为4*n+10(线段树的经典大小),初始值全为0
    vector<struct node> tree_s(n * 4 + 10, {0, 0, 0, 0, 0, 0}), tree_t(n * 4 + 10, {0, 0, 0, 0, 0, 0});
    build(1, 1, n, tree_s, s);  // 构建字符串s的线段树
    build(1, 1, n, tree_t, t);  // 构建字符串t的线段树

    // 处理每个查询操作
    while (q--) {
        int k;
        cin >> k;  // 输入要交换的位置(从1开始)
        // 更新s的线段树:将k位置改为t的k-1位置的字符(字符串下标从0开始)
        update(1, 1, n, k, tree_s, t[k - 1]);
        // 更新t的线段树:将k位置改为s的k-1位置的字符
        update(1, 1, n, k, tree_t, s[k - 1]);
        swap(s[k-1], t[k-1]);  // 交换原字符串s和t中k-1位置的字符
        // 输出s的red子序列数量与t的red子序列数量的差值
        cout << tree_s[1].red - tree_t[1].red << endl;
    }
    return 0;
}