题意:给出一个长为n,只含有AB字符的字符串,有q次操作,第一种是[L,R]内的字符A变成B,B变成A,第二种是询问L,R,A,B
按这种方式求和:。
思路:
建立线段树,每个节点都是一个矩阵,然后区间修改,区间求和即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 5;
const ll mod = 1e9 + 7;
int n, q, lz[N << 2];
char s[N];
struct node {
ll m[2][2];
node() {
memset(m, 0, sizeof m);
}
} no[N << 2][2], A, B;
node operator *(node a, node b) {
node ans;
for(int i = 0; i < 2; i++)
for(int j = 0; j < 2; j++)
for(int k = 0; k < 2; k++)
ans.m[i][j] = (ans.m[i][j] + a.m[i][k] * b.m[k][j] % mod) % mod;
return ans;
}
void pushup(int rt) {
no[rt][0] = no[rt << 1][0] * no[rt << 1 | 1][0];
no[rt][1] = no[rt << 1][1] * no[rt << 1 | 1][1];
}
void pushdown(int rt) {
if(lz[rt]) {
swap(no[rt << 1][0], no[rt << 1][1]);
swap(no[rt << 1 | 1][0], no[rt << 1 | 1][1]);
lz[rt << 1] ^= 1;
lz[rt << 1 | 1] ^= 1;
lz[rt] = 0;
}
}
void build(int l, int r, int rt) {
if(l == r) {
if(s[l] == 'A')
no[rt][0] = A, no[rt][1] = B;
else
no[rt][0] = B, no[rt][1] = A;
return;
}
int m = l + r >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
pushup(rt);
}
void change(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) {
swap(no[rt][0], no[rt][1]);
lz[rt] ^= 1;
return;
}
pushdown(rt);
int m = l + r >> 1;
if(L <= m)
change(L, R, l, m, rt << 1);
if(R > m)
change(L, R, m + 1, r, rt << 1 | 1);
pushup(rt);
}
node query(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R)
return no[rt][0];
node ans;
ans.m[1][1] = ans.m[0][0] = 1;
pushdown(rt);
int m = l + r >> 1;
if(L <= m)
ans = ans * query(L, R, l, m, rt << 1);
if(R > m)
ans = ans * query(L, R, m + 1, r, rt << 1 | 1);
return ans;
}
int main() {
A.m[0][0] = A.m[1][0] = A.m[1][1] = 1;
B.m[0][0] = B.m[0][1] = B.m[1][1] = 1;
scanf("%d%d%s", &n, &q, s + 1);
build(1, n, 1);
while(q--) {
int l, r, op;
ll a, b;
scanf("%d%d%d", &op, &l, &r);
if(op == 1) {
change(l, r, 1, n, 1);
} else {
scanf("%lld%lld", &a, &b);
node ans = query(l, r, 1, n, 1);
node kk;
kk.m[0][0] = a, kk.m[0][1] = b;
kk = kk * ans;
printf("%lld %lld\n", kk.m[0][0], kk.m[0][1]);
}
}
return 0;
}