这个题难点不在线段树上,事实上只要解决了如何求一个01串有多少个不同子串的问题之后,基本上就是一马平川了。所以我队因为不会计数比赛的时候GG了。。。之后围观了叉姐的题解学会了计数,就xjb写完了。
#include
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=105000;
struct mat{
ll a[3][3];
void init(int tag){
memset(a, 0, sizeof(a));
if(tag==0){
a[0][0]=a[0][1]=a[0][2]=a[1][1]=a[2][2]=1;
}
else {
a[0][0]=a[1][0]=a[1][1]=a[1][2]=a[2][2]=1;
}
}
void rev(){
swap(a[0][0], a[1][1]);
swap(a[0][1], a[1][0]);
swap(a[0][2], a[1][2]);
}
};
mat operator*(const mat& a, const mat& b){
mat ans;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
ans.a[i][j]=0;
for(int k=0;k<3;k++){
ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j])%mod;
}
}
}
return ans;
}
char s[maxn];
int n, m;
mat rec[maxn<<2];
int lz[maxn<<2];
void pushdown(int u){
if(!lz[u])return ;
rec[2*u].rev();
lz[2*u]^=1;
rec[2*u+1].rev();
lz[2*u+1]^=1;
lz[u]=0;
}
void pushup(int u){
rec[u]=rec[2*u+1]*rec[2*u];
}
void build(int u, int l, int r){
lz[u]=0;
if(l==r){
rec[u].init(s[l]-'0');
return ;
}
int mid=(l+r)>>1;
build(2*u, l, mid);
build(2*u+1, mid+1, r);
pushup(u);
}
void update(int u, int ql, int qr, int l, int r){
if(ql>r||qr >1;
pushdown(u);
update(2*u, ql, qr, l, mid);
update(2*u+1, ql, qr, mid+1, r);
pushup(u);
}
mat query(int u, int ql, int qr, int l, int r){
if(ql<=l&&r<=qr){
return rec[u];
}
int mid=(l+r)>>1;
pushdown(u);
mat ret;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++)ret.a[i][j]=(i==j);
}
if(mid>=ql)ret=query(2*u, ql, qr, l, mid)*ret;
if(mid+1<=qr)ret=query(2*u+1, ql, qr, mid+1, r)*ret;
return ret;
}
int main(){
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &m);
scanf("%s", s+1);
build(1, 1, n);
for(int i=1;i<=m;i++){
int tag, l, r;
scanf("%d%d%d", &tag, &l, &r);
if(tag==1){
update(1, l, r, 1, n);
}
else {
mat m=query(1, l, r, 1, n);
printf("%lld\n", (m.a[0][2]+m.a[1][2])%mod);
}
}
}
}