比赛的时候想到这个公式,可惜对于中间那部分处理不得当,导致要记录的东西太多,最后不了了之。
规律很好推理,就是从头到尾的s1*b1+s3*b2。。。。b1等于项数,b2等于项数减2,然后就是维护与更新了。
写的时候一开始没将串翻倍,一直WA,估计某个地方爆longlong了,改了好久都WA,怒将串翻倍,搞定。
附代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define delf LL m=(l+r)>>1
#define LL long long int
using namespace std;
const int MAX=200010;
const LL MOD=1000000007;
LL tsum[2][MAX<<2]; //记录每个区间以最左端为起点的前缀和(1当前位开始0当前下一位开始)
LL sum[2][MAX<<2]; //记录偶数项的和和奇数项的和(1当前位开始0当前下一位开始)
char ch[MAX];
LL n;
struct node
{
LL sum0;
LL sum1;
LL tsum0;
LL tsum1;
node()
{
sum0=sum1=tsum0=tsum1=0;
}
};
void pushup(LL l,LL r,LL rt)
{
delf;
int len=(m-l+1);
if (len%2==0)
{
sum[0][rt]=(sum[0][rt<<1]+sum[0][rt<<1|1])%MOD;
tsum[0][rt]=(tsum[0][rt<<1]+(r-m)*sum[0][rt<<1]%MOD+tsum[0][rt<<1|1])%MOD;
sum[1][rt]=(sum[1][rt<<1]+sum[1][rt<<1|1])%MOD;
tsum[1][rt]=(tsum[1][rt<<1]+(r-m)*sum[1][rt<<1]%MOD+tsum[1][rt<<1|1])%MOD;
}
else
{
sum[0][rt]=(sum[0][rt<<1]+sum[1][rt<<1|1])%MOD;
tsum[0][rt]=(tsum[0][rt<<1]+(r-m)*sum[0][rt<<1]%MOD+tsum[1][rt<<1|1])%MOD;
sum[1][rt]=(sum[1][rt<<1]+sum[0][rt<<1|1])%MOD;
tsum[1][rt]=(tsum[1][rt<<1]+(r-m)*sum[1][rt<<1]%MOD+tsum[0][rt<<1|1])%MOD;
}
return ;
}
void build(LL l,LL r,LL rt)
{
tsum[0][rt]=tsum[1][rt]=0;
sum[0][rt]=sum[1][rt]=0;
if (l==r)
{
if (l>n)
l=l-n;
LL v=ch[l]-'0';
sum[1][rt]=v;
tsum[1][rt]=v;
return ;
}
delf;
build (lson);
build (rson);
pushup(l,r,rt);
return ;
}
void update(LL k,LL v,LL l,LL r,LL rt)
{
if (l==r)
{
sum[1][rt]=tsum[1][rt]=v;
return ;
}
delf;
if (k<=m)
update(k,v,lson);
else
update(k,v,rson);
pushup(l,r,rt);
return ;
}
node query(LL L,LL R,LL l,LL r,LL rt)
{
if (L==l&&r==R)
{
node s;
s.sum0=sum[0][rt];
s.sum1=sum[1][rt];
s.tsum0=tsum[0][rt];
s.tsum1=tsum[1][rt];
return s;
}
delf;
if (R<=m)
return query(L,R,lson);
else if (L>m)
return query(L,R,rson);
else
{
delf;
node s;
node s1=query(L,m,lson);
node s2=query(m+1,R,rson);
int len=(m-L+1);
if (len%2==0)
{
s.sum0=(s1.sum0+s2.sum0)%MOD;
s.sum1=(s1.sum1+s2.sum1)%MOD;
s.tsum0=(s1.tsum0+(R-m)*s1.sum0%MOD+s2.tsum0)%MOD;
s.tsum1=(s1.tsum1+(R-m)*s1.sum1%MOD+s2.tsum1)%MOD;
}
else
{
s.sum0=(s1.sum0+s2.sum1)%MOD;
s.sum1=(s1.sum1+s2.sum0)%MOD;
s.tsum0=(s1.tsum0+(R-m)*s1.sum0%MOD+s2.tsum1)%MOD;
s.tsum1=(s1.tsum1+(R-m)*s1.sum1%MOD+s2.tsum0)%MOD;
}
return s;
}
}
LL gets(LL a1,LL d,LL t)
{
LL s1=a1*(t%MOD)%MOD;
LL t1=t-1;
if (t%2)
t1=t1/2;
else
t=t/2;
t=t%MOD;
t1=t1%MOD;
LL s2=(t*t1%MOD)*d%MOD;
s1=(s1+s2)%MOD;
return s1;
}
LL solve(LL l,LL r)
{
LL nn=2*n;
LL t1=(l-1)/nn+1; //l处于哪个循环节
LL t2=(r-1)/nn+1; //r处于哪个循环节
LL l1=l%nn;
LL r1=r%nn;
if (l1==0)
l1=nn;
if (r1==0)
r1=nn;
if (t1==t2)
return query(l1,r1,1,nn,1).tsum1%MOD;
LL t=(t2-t1-1); //l所处的循环节和r所处的循环节中间有几个循环节
LL s;
node s1=query(l1,nn,1,nn,1); //前缀部分
node s2=query(1,r1,1,nn,1); //后缀部分
s=(s1.tsum1+(((r-l+1)-(nn-l1+1))%MOD)*s1.sum1)%MOD;
if ((nn-l1+1)%2==0)
s=(s+s2.tsum1)%MOD;
else
s=(s+s2.tsum0)%MOD;
//处理中间的循环节部分,最坑点
if (t>0)
{
if ((nn-l1+1)%2==0) //开始循环前偶数个数
s=(s+(t%MOD)*tsum[1][1]%MOD+gets(r1,nn,t)*sum[1][1]%MOD)%MOD;
else //开始循环前奇数个数
s=(s+(t%MOD)*tsum[0][1]%MOD+gets(r1,nn,t)*sum[0][1]%MOD)%MOD;
}
return s%MOD;
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%s",ch+1);
n=strlen(ch+1);
build (1,2*n,1);
int q;
scanf("%d",&q);
while (q--)
{
int p;
LL a,b;
scanf("%d",&p);
scanf("%lld%lld",&a,&b);
if (p==1)
{
update(a,b,1,2*n,1);
update(a+n,b,1,2*n,1);
}
else
{
LL ans=solve(a,b)%MOD;
printf("%lld\n",ans);
}
}
}
}