#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;
}