题意:给一个0~9组成的串,有两种操作,1是改变某个位置pos的值,2是计算某一段l~r的
G(l, r) = Sl - Sl+1 + Sl+2 - ... + (-1)r-lSr
不过,这个串是无限周期循环的,输入给的是一个循环节内的内容,而且l和r的范围会很大。
思路:线段树。首先我们需要推出一个公式,比如对于串abcde,G(1,5) =5*a+3*c+1*e,用语言描述就是实际上只有从左到右的奇数位参与求和,第一个数的系数是区间长度,往后逐个递减2。所以,线段树需要维护4个内容,区间内的奇数位和,偶数位和,G(区间左边,区间右边),G(区间左边+1,区间右边),具体维护方法见代码。这样就可以计算循环节内的G了。
但是循环节外的怎么办,其实我们可以把它分为三段,中间那一段是完成的若干个循环节,最左边和最右边是另外两段,这两段可能是不完整的。然后分别计算三段再合并就可以了。其中,中间那一段可能跨过了非常多个循环节,不能逐个合并,这里有用到了快速幂的思想,具体见代码,三段合并后,就是长区间的结果。
这题坑了我好久,主要是两个问题,大范围没有去去模转换到循环节内。还有就是爆long long的问题。下面上代码。。。
#include<iostream> #include<cmath> #include<queue> #include<vector> #include<algorithm> #include<string.h> #include<cstdio> using namespace std; #define maxn 100010 #define ll long long #define mod 1000000007ull char P[maxn]; ll len; struct node{ ll l,r; ll sum1; //奇数位和 ll sum0; //偶数位和 ll val1; //奇数位阶梯和 ll val0; //偶数位阶梯和 }; node tree[maxn*4]; void push_up(node& p,node& lch,node& rch){ ll d=rch.r-rch.l; rch.l=lch.r+1; rch.r=rch.l+d; p.l=lch.l; p.r=rch.r; ll llen=lch.r-lch.l+1; ll rlen=rch.r-rch.l+1; p.val1=lch.val1+lch.sum1*(rlen%mod); p.val0=lch.val0+lch.sum0*(rlen%mod); p.sum1=lch.sum1; p.sum0=lch.sum0; if(llen&1){ p.val1+=rch.val0; p.val0+=rch.val1; p.sum1+=rch.sum0; p.sum0+=rch.sum1; }else{ p.val1+=rch.val1; p.val0+=rch.val0; p.sum1+=rch.sum1; p.sum0+=rch.sum0; } p.val1%=mod; p.val0%=mod; p.sum1%=mod; p.sum0%=mod; } void build_tree(ll n,ll l,ll r){ tree[n].l=l; tree[n].r=r; if(l==r){ tree[n].val1=tree[n].sum1=P[l]-'0'; tree[n].val0=tree[n].sum0=0; return; } ll mid=(l+r)/2; build_tree(n<<1,l,mid); build_tree((n<<1)|1,mid+1,r); push_up(tree[n],tree[n<<1],tree[(n<<1)|1]); } node query(ll n,ll l,ll r){ if(tree[n].l==l&&tree[n].r==r){ return tree[n]; } ll mid=(tree[n].l+tree[n].r)/2; if(r<=mid){ return query(n<<1,l,r); }else{ if(l>mid){ return query((n<<1)|1,l,r); }else{ node re; node lch=query(n<<1,l,mid); node rch=query((n<<1)|1,mid+1,r); push_up(re,lch,rch); return re; } } } void update(ll n,ll pos,ll val){ if(tree[n].l==tree[n].r){ tree[n].val1=tree[n].sum1=val; tree[n].val0=tree[n].sum0=0; return; } ll mid=(tree[n].l+tree[n].r)/2; if(pos<=mid){ update(n<<1,pos,val); }else{ update((n<<1)|1,pos,val); } push_up(tree[n],tree[n<<1],tree[(n<<1)|1]); } //长区间快速合并 node mul(ll n){ node one=tree[1]; node re; bool flag=1; while(n){ if(n&1){ if(flag){ re=one; flag=0; }else{ node tmp; push_up(tmp,one,re); re=tmp; } } node tmp; node oneL=one; node oneR=one; push_up(tmp,oneL,oneR); one=tmp; n>>=1; } return re; } int main(){ int t; cin>>t; while(t--){ scanf("%s",P+1); len=strlen(P+1); build_tree(1,1,len); ll q; cin>>q; for(int i=1;i<=q;i++){ ll op; scanf("%lld",&op); if(op==1){ //update ll a,b; scanf("%lld%lld",&a,&b); update(1,a,b); }else{ //query ll a,b; scanf("%lld%lld",&a,&b); ll cnt=(b-1)/len-(a-1)/len; if(cnt>1){ node M=mul(cnt-1); ll ls=a%len; if(!ls)ls=len; ll rt=b%len; if(!rt)rt=len; node lch=query(1,ls,len); node rch=query(1,1,rt); node tmp; push_up(tmp,lch,M); node ans; push_up(ans,tmp,rch); printf("%lld\n",ans.val1%mod); }else if(cnt==1){ ll ls=a%len; if(!ls)ls=len; ll rt=b%len; if(!rt)rt=len; node lch=query(1,ls,len); node rch=query(1,1,rt); node ans; push_up(ans,lch,rch); printf("%lld\n",ans.val1%mod); }else{ a%=len; if(!a)a=len; b%=len; if(!b)b=len; node ans=query(1,a,b); printf("%lld\n",ans.val1%mod); } } } } return 0; }