zoj 3813 Alternating Sum(2014ACMICPC Regional 牡丹江站网络赛 E)

来源:互联网 发布:tsp问题算法源代码 编辑:程序博客网 时间:2024/04/29 10:28

 

1.http://blog.csdn.net/dyx404514/article/details/39122743

思路:题目意思很清楚了,这里只说思路。


设区间[L,R],区间长度为len=(R-L+1),设F[i]表示G(i,i)+G(i,i+1)+......G(i,R)。那么对于区间[L,R],询问的答案即为Ans[L,R]=F[L]+F[L+1]+......+F[R]。容易得到G[i,j]=Si-G(i+1,j),所以F[i]=(R-i+1)*Si-F[i+1]。即F[i]+F[i+1]=(R-i+1)*Si。

那么Ans[L,R]=len*SL+(len-2)*S(i+2)+.....SR(len为奇数)或

len*SL+(len-2)*(L+2)+......+2*S(R-1)(len为偶数)。

那么对于给定区间[L,R]的答案可以用线段树维护,我的线段树维护4个值,sum[0]表示区间中偶数位数的和,sum[1]表示区间中奇数位置的和,tsum[0]表示Ans[L+1,R],tsum[1]表示Ans[L,R]。

如区间[3,7]={2,3,4,5,6},那么sum[0]=3+5=8,sum[1]=2+4+6=12,tsum[0]=4*3+2*5=22,tsum[1]=5*2+3*4+1*6=28。对于区间长度为偶数的类似。

现在考虑合并两个区间,对于区间p,其左儿子为lson,右儿子为rson。sum[0],sum[1]很好合并,只需要考虑左儿子长度的奇偶性,既可以完成合并。对于tsum[0],其左部分(由左儿子的信息得到的部分)为左儿子的tsum[0]加上左儿子的sum[0]乘以右儿子的长度(自己推推就能知道)。右部分要根据左儿子长度的奇偶性来决定是右儿子的tsum[0]还是tsum[1]。对于tsum[1]也类似。

那么线段树部分就结束了。注意到题目中的数字区间是一个模式串重复无数次的一个无限长的串,那么所给的区间可能会横跨很多个模式串S,我们的线段树只是对于模式串S的线段树,那么对于超出一个模式串的部分不能只用线段树来解决。如果区间[L,R]横跨多个模式串,那么将区间L,R分成三部分,前缀pre,中间部分mid,后缀suf,前缀表示区间[L,R]第一个不完整的模式串(可为空),后缀表示最后一个不完整的模式串(可为空),中间部分为中间横跨的多个完整的模式串(可为空)。那么pre,suf可以用线段树求出,类似于区间合并的方法,这里不再赘述。设mid包括n个完整的模式串,suf的长度为Len。还是按照区间合并的思想,不过这里n可能很大,不能直接一个一个地合并,事实上可以推出来,具体公式请自己推吧,本人很懒。。。。

这里还有一个问题,如果模式串为奇数,那么合并的时候很烦人,要间隔地考虑,这里我将模式串扩大两倍,保证模式串为偶数,那么在求mid的值得时候就不需要考虑奇偶性了。但是如果将模式串扩大两倍的话,在修改操作的时候,一定要记住要修改两个位置(这里忘了WA了10+发。。。。。。)。恩,大概就是这样,下面是代码:(内存耗得飞起。。。。速度也比较慢~~)


#include <iostream>#include <string.h>#include <stdio.h>#include <algorithm>#define maxn 200010#define mid ((t[p].l+t[p].r)>>1)#define ls (p<<1)#define rs (ls|1)#define ll long long#define mod 1000000007using namespace std;char st[maxn];struct tree{    ll l,r;    ll sum[2],tsum[2];}t[maxn<<2];void pushup(int p){    ll l=t[ls].r-t[ls].l+1;    ll r=t[rs].r-t[rs].l+1;    if(l%2)    {        t[p].sum[0]=(t[ls].sum[0]+t[rs].sum[1])%mod;        t[p].sum[1]=(t[ls].sum[1]+t[rs].sum[0])%mod;        t[p].tsum[0]=(t[ls].tsum[0]+r*t[ls].sum[0]%mod+t[rs].tsum[1])%mod;        t[p].tsum[1]=(t[ls].tsum[1]+r*t[ls].sum[1]%mod+t[rs].tsum[0])%mod;    }    else    {        t[p].sum[0]=(t[ls].sum[0]+t[rs].sum[0])%mod;        t[p].sum[1]=(t[ls].sum[1]+t[rs].sum[1])%mod;        t[p].tsum[0]=(t[ls].tsum[0]+r*t[ls].sum[0]%mod+t[rs].tsum[0])%mod;        t[p].tsum[1]=(t[ls].tsum[1]+r*t[ls].sum[1]%mod+t[rs].tsum[1])%mod;    }}void build(int p,int l,int r){    t[p].l=l,t[p].r=r;    t[p].sum[0]=t[p].sum[1]=t[p].tsum[0]=t[p].tsum[1]=0;    if(l==r)    {        t[p].sum[0]=t[p].tsum[0]=0;        t[p].sum[1]=t[p].tsum[1]=st[l]-'0';        return;    }    build(ls,l,mid);    build(rs,mid+1,r);    pushup(p);}void modify(int p,int po,ll d){    if(t[p].l==t[p].r)    {        t[p].sum[1]=t[p].tsum[1]=d;        return;    }    if(po>mid)    modify(rs,po,d);    else    modify(ls,po,d);    pushup(p);}tree query(int p,ll l,ll r){    tree tmp;    if(t[p].l==l&&t[p].r==r)    {        return t[p];    }    if(l>mid)    return query(rs,l,r);    else if(r<=mid)    return query(ls,l,r);    else    {        tree t1=query(ls,l,mid);        tree t2=query(rs,mid+1,r);        tmp.l=t1.l,tmp.r=t2.r;        ll l=t1.r-t1.l+1;        ll r=t2.r-t2.l+1;        if(l%2){            tmp.sum[0]=(t1.sum[0]+t2.sum[1])%mod;            tmp.sum[1]=(t1.sum[1]+t2.sum[0])%mod;            tmp.tsum[0]=(t1.tsum[0]+r*t1.sum[0]%mod+t2.tsum[1])%mod;            tmp.tsum[1]=(t1.tsum[1]+r*t1.sum[1]%mod+t2.tsum[0])%mod;        }        else{            tmp.sum[0]=(t1.sum[0]+t2.sum[0])%mod;            tmp.sum[1]=(t1.sum[1]+t2.sum[1])%mod;            tmp.tsum[0]=(t1.tsum[0]+r*t1.sum[0]%mod+t2.tsum[0])%mod;            tmp.tsum[1]=(t1.tsum[1]+r*t1.sum[1]%mod+t2.tsum[1])%mod;        }        return tmp;    }}ll getsum(ll num,ll len,ll left,int typ){    if(num==0)    return 0;    ll sum=0;    sum=num%mod*t[1].tsum[typ]%mod;    ll tt;    if(num%2)    tt=((num-1)/2)%mod*(num%mod);    else    tt=((num-1)%mod)*((num/2)%mod);    tt%=mod;    ll tmp=(num%mod*left%mod+tt*len%mod)%mod;    sum=(sum+tmp*t[1].sum[typ]%mod)%mod;    return sum;}int main(){  // freopen("dd.txt","r",stdin);    int ncase;    scanf("%d",&ncase);    while(ncase--)    {        scanf("%s",st);        int len=strlen(st);        for(int i=0;i<len;i++)        {            st[i+len]=st[i];        }        len*=2;        build(1,0,len-1);        int q;        scanf("%d",&q);        while(q--){            int typ;            ll ans=0,l,r;            scanf("%d",&typ);            if(typ==1)            {                int x,d;                scanf("%d%d",&x,&d);                modify(1,x-1,d);                modify(1,x-1+(len/2),d);            }            else            {                scanf("%lld%lld",&l,&r);                l--,r--;                ll lpo=l/len,rpo=r/len;                ll L=l%len,R=r%len;                if(lpo==rpo)                {                    ans=query(1,L,R).tsum[1];                }                else                {                    ll Len=((r-l+1)-(len-L))%mod;                    tree t1=query(1,L,len-1);                    tree t2=query(1,0,R);                    ans=(ans+t1.tsum[1]+Len*t1.sum[1]%mod)%mod;                    if((len-L)%2)                    ans=(ans+t2.tsum[0])%mod;                    else                    ans=(ans+t2.tsum[1])%mod;                    if((len-L)%2)                    ans=(ans+getsum(rpo-lpo-1,len,R+1,0))%mod;                    else                    ans=(ans+getsum(rpo-lpo-1,len,R+1,1))%mod;                }                printf("%lld\n",ans);            }        }    }    return 0;}






2.

http://www.cnblogs.com/gj-Acit/p/3961971.html


给定序列P,定义序列S为P反复重复得到的一个无穷长的序列:

      if P = 3423537, then S = 3423537342353734235373423537...

再定义G(lr) = Sl - Sl+1 + Sl+2 - ... + (-1)r-lSr

给两种操作:

1 x d:将序列P的第x想改为d(d是一个简单数字0~9)

2 l r  :求sum of G(ij) that l <= i <= j <= r.

 

比赛时看到这个题,以为是求G(l, r),然后就高高兴兴用线段树开始敲了,快敲完才知道是求对任意的l <= i <= j <= r,求G(i, j) 的和

比赛快完了才想到思路,没时间敲了,今天花了大半天时间终于A掉。

按照题目要求,求sum of G(ij) ,所以先把它化简,找下规律,很容易可以得到以下规律:


Sum{ G(i, j) } = (r - l + 1) * S[l]  + (r - l - 1) * S[l + 2] + (r - l - 3) * S[l + 4] + ... ...  + S[r]             (R-l+1)为奇数
                                                                                                                            + 2 * S[r-1]       (R-l+1)为偶数

 

注意上面相邻两项之间下标差都是2,由于不知道是需要用2*S[i] + 4*S[i-2]...  还是要用S[i] + 3*S[i-2]...,所以都保存起来

然后我们定义F[i][0] = S[i] + 3 * S[i-2] + 5 * S[i-4] +  ... ...

                 F[i][1] = 2 * S[i] + 4 * F[i-2] + 6 * F[i-4] +  ... ...

再定义P[i] = S[i] + S[i - 2] + S[i - 4] + ... ...

经过简单计算可以得出: 最后题目要求的Sum{ G(l, r) } = F[r] - F[l - 2] - k * P[l - 2]  (这里的F的第二维取决于(r-l+1)是奇还是偶,通过计算可以得到 令 len = (r - l + 1)  ,  那么 k = len + len % 2)  )

 

然后定义线段树节点:

1 struct Node2 {3     int l, r;4     LL P[2], F[2][2];5 }t[MAXN<<2];

其中:
P[0] = S[r] + S[r - 2] + S[r - 4] + ... ... + S[k]   (k >= l)
P[0] = S[r-1] + S[r - 3] + S[r - 5] + ... ... + S[k]   (k >= l)

F[0][0] = S[r] + 3 * S[r - 2] + 5 * S[r - 4] + ... ... + x * S[k]  (k >= l)
F[0][1] = 2*S[r] + 4*S[r - 2] + 6*S[r - 4] + ... ... + x * S[k]  (k >= l)
F[1][0] = S[r-1] + 3 * S[r - 3] + 5 * S[r - 5] + ... ... + x * S[k]  (k >= l)
F[1][1] = 2*S[r-1] + 4*S[r - 3] + 6*S[r - 5] + ... ... + x * S[k]  (k >= l)

 

然后做线段树的单电修改,修改某个叶子节点后往上更新,  rc和lc对应于当前节点k的右子节点和左子节点,  len是rc节点的区间长度

复制代码
1     rep(i, 0, 1) {2         rep(j, 0, 1) {3             t[k].F[i][j] = ( t[rc].F[i][j] + t[lc].F[(len-i) & 1][j]4                             + t[lc].P[(len-i) & 1] * (len-i + (len-i)%2) ) % MOD;5         }6         t[k].P[i] = (t[rc].P[i] + t[lc].P[(len - i) & 1]) % MOD;7     }
复制代码

 

接下来写两个查询,分别是查询[1, p]的P值, 和查询[1,p]的F值, flag用来标注是2,4,6,8... ... 还是 1, 3, 5, 7 ... ...增长

复制代码
 1 LL query_pre(int k, int p) 2 { 3     if(t[k].l == t[k].r) return t[k].P[0]; 4  5     int mid = (t[k].l + t[k].r) >> 1; 6  7     if(p <= mid) return query_pre(k<<1, p); 8  9     int re = (p - mid);10     return (t[k<<1].P[re&1] + query_pre(k<<1|1, p)) % MOD;11 }12 13 LL query_F(int k, int p, int flag)14 {15     if(t[k].l == t[k].r) return t[k].F[0][flag];16 17     int mid = (t[k].l + t[k].r) >> 1;18 19     if(p <= mid) return query_F(k<<1, p, flag);20 21     int re = p - mid;22 23     return (t[k<<1].F[re&1][flag] + t[k<<1].P[re&1] * (re + re%2) + query_F(k<<1|1, p, flag)) % MOD;24 }
复制代码

 

这样,在不考虑 l 和 r 大于给定序列长度n的情况下,原题已经可解,答案就是:

query_F(1, r) - query_F(1, l - 2) - query_Pre(1, l - 2) * (len + len % 2)        (其中len = r - l + 1)

 

 

然后再考虑l 和 r比较大的情况,由于虽然l 和 r 比较大,但是给定序列的长度是小于1e5的, 所以说显然中间过程是可以直接推算出来的, 事实上,设原序列长度为n, len = (r - l + 1), 那么最初给出的序列会出现 k = (len - 1) / n 次,而这 k 次序列可以看做是 出现了k次F[n],以及 出现了 a * P[n], (a + n) * P[n], (a + 2 n) * P[n]... ...(a + (k-1)*n) * P[n]

这正好是一个等差数列, 所以计算新的F[r] (r >> n)时, F[n] = query(r) + k * F[n] + P[n] * (a + (a + d) + (a + 2 * d) + ... ... + (a + (k-1) * d) ).

注意, 上面的等差数列首项a还未确定, 公差d也还未确定, 也就是说,只要计算出a 和 d, 就计算出了我们的要求的答案。

 

注意到如果n(原序列长度)是偶数,又因为增量是2,所以可以计算出公差 d = n,而首项 a = p + p % 2  , 其中p = (r - 1) % n + 1,也就是最后一个剩下序列的长度

如果n是奇数,会出现有时我们需要的是F[n], 有时需要的又是F[n-1],这是只要理解为两个等差数列就可以了,其中公差都是d = 2 * n, 但是首项不同

 

代码还有很多需要注意的小细节,很多地方需要反复计算(比如那两个等差数列),反正就是比较麻烦

复制代码
  1 #include <map>  2 #include <set>  3 #include <stack>  4 #include <queue>  5 #include <cmath>  6 #include <ctime>  7 #include <vector>  8 #include <cstdio>  9 #include <cctype> 10 #include <cstring> 11 #include <cstdlib> 12 #include <iostream> 13 #include <algorithm> 14 using namespace std; 15 #define INF 1e9 16 #define inf (-((LL)1<<40)) 17 #define lson k<<1, L, mid 18 #define rson k<<1|1, mid+1, R 19 #define mem0(a) memset(a,0,sizeof(a)) 20 #define mem1(a) memset(a,-1,sizeof(a)) 21 #define mem(a, b) memset(a, b, sizeof(a)) 22 #define FOPENIN(IN) freopen(IN, "r", stdin) 23 #define FOPENOUT(OUT) freopen(OUT, "w", stdout) 24 #define rep(i, a, b) for(int i = a; i <= b; i ++) 25 template<class T> T CMP_MIN(T a, T b) { return a < b; } 26 template<class T> T CMP_MAX(T a, T b) { return a > b; } 27 template<class T> T MAX(T a, T b) { return a > b ? a : b; } 28 template<class T> T MIN(T a, T b) { return a < b ? a : b; } 29 template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; } 30 template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b;    } 31  32 //typedef __int64 LL; 33 typedef long long LL; 34 const int MAXN = 110000; 35 const int MAXM = 1000006; 36 const double eps = 1e-10; 37 const LL MOD = 1000000007; 38  39 struct Node 40 {            // P[0] = S[r] + S[r-2] + S[r-4]...    P[1] = S[r-1] + S[r-3] + S[r-5] + ... 41     int l, r;//F[0][0] = S[r] + 3 * S[r-2] + ...    F[0][1] = 2 * S[r] + 4 * S[r-2] + ... 42     LL P[2], F[2][2];// F[1][0] = S[r-1] + 3 * S[r - 3] + ...  F[1][1] = 2 * S[r-1] + 4 * S[r-3] + ... 43 }t[MAXN<<2]; 44 int n, cas, q; 45 char str[110000]; 46  47 //建树 48 void build(int k, int L, int R) 49 { 50     t[k].l = L; 51     t[k].r = R; 52     t[k].P[0] = t[k].P[1] = 0;//P和F统统初始化为0 53     rep (i, 0, 1) rep(j, 0, 1) 54         t[k].F[i][j] = 0; 55     if(L == R) return ; 56  57     int mid = (R + L) >> 1; 58     build(k<<1, L, mid); 59     build(k<<1|1, mid + 1, R); 60 } 61  62 //从子节点更新父节点 63 void push_up(int k) 64 { 65     int lc = k<<1, rc = k<<1|1; 66     int re = t[rc].r - t[rc].l + 1;//右侧节点长度 67     rep(i, 0, 1) { 68         rep(j, 0, 1) { 69             if(re==1 && i==1) {//特殊处理右侧只有一个节点的情况 70                 t[k].F[i][j] = t[lc].F[0][j]; 71                 continue; 72             } 73             t[k].F[i][j] = ( t[rc].F[i][j] + t[lc].F[(re-i) & 1][j] 74                             + t[lc].P[(re-i) & 1] * (re-i + (re-i)%2) ) % MOD; 75         } 76         t[k].P[i] = (t[rc].P[i] + t[lc].P[(re - i) & 1]) % MOD; 77     } 78 } 79  80 //将位置为p的节点更新为val 81 void update(int k, int p, int val) 82 { 83     if(t[k].l == t[k].r) { 84         t[k].P[0] = t[k].F[0][0] = val; 85         t[k].F[0][1] = 2 * val; 86         return; 87     } 88     int m = (t[k].l + t[k].r) >> 1; 89  90     if(p <= m) update(k<<1, p, val); 91  92     else update(k<<1|1, p, val); 93  94     push_up(k); 95 } 96  97 LL query_pre(int k, int p)//询问S[p] + S[p-2] + ... 98 { 99     if(t[k].l == t[k].r) return t[k].P[0];100 101     int mid = (t[k].l + t[k].r) >> 1;102 103     if(p <= mid) return query_pre(k<<1, p);104 105     int re = (p - mid);106     return (t[k<<1].P[re&1] + query_pre(k<<1|1, p)) % MOD;107 }108 109 LL query_F(int k, int p, int flag)//询问F[p][flag] + F[p-2][flag] + ...110 {111     if(t[k].l == t[k].r) return t[k].F[0][flag];112 113     int mid = (t[k].l + t[k].r) >> 1;114 115     if(p <= mid) return query_F(k<<1, p, flag);116 117     int re = p - mid;118 119     return (t[k<<1].F[re&1][flag] + t[k<<1].P[re&1] * (re + re%2) + query_F(k<<1|1, p, flag)) % MOD;120 }121 122 LL get_mul(LL fir, LL d, LL k)//计算首项为fir,公差为d,项数为k的等差数列和123 {124     LL tmp1 = (k % MOD) * (fir % MOD) % MOD;125     LL tmp2 = k;126     if( k % 2 == 0 )127         tmp2 = k / 2 % MOD * ((k-1) % MOD) % MOD;128     else129         tmp2 = k % MOD * ((k-1) / 2 % MOD)  % MOD;130     tmp2 = tmp2 * (d % MOD) % MOD;131     return (tmp1 + tmp2) % MOD;132 }133 134 //计算F[p][flag] + F[p-2][flag] + ... ...(这里p >> n)135 LL get_F(LL p, LL flag)136 {137     LL k = (p - 1) / n;138     p = (p - 1) % n + 1;139     LL ans = query_F(1, p, flag);140     if(n % 2 == 0 && k > 0) {//这里n是偶数,只有一个等差数列141         ans = (ans + k % MOD * t[1].F[p&1][flag] ) % MOD;142                     //首项为p + p%2, 公差为n, 项数为k143         ans = (ans + get_mul(p + p % 2, n, k) * t[1].P[p&1] % MOD) % MOD;144     }145     else if(n % 2 == 1 && k > 0) {//n是奇数,会存在两个等差数列146         LL tmp = p % 2 ? -1 : 1;147 148         ans = (ans + (k+1)/2 % MOD * t[1].F[p&1][flag]) % MOD;149 150         ans = (ans + k/2 % MOD * t[1].F[!(p&1)][flag]) % MOD;151 152         ans = (ans + get_mul(p + p%2, n*2, (k+1)/2) * t[1].P[p&1] % MOD) % MOD;153 154         ans = (ans + get_mul(p + p%2 + n + tmp, n*2, k/2) * t[1].P[!(p&1)] % MOD) % MOD;155     }156     return ans;157 }158 159 //拿到P[p] + P[p-2] + P[p-4] + ... ... (p >> n)160 LL get_P(LL p)161 {162     LL k = (p - 1) / n;163     p = (p - 1) % n + 1;164     LL ans = query_pre(1, p);165     if(n % 2 == 0 && k > 0) {166         ans = (ans + k % MOD * t[1].P[p&1]) % MOD;167     }168     else if(n % 2 == 1 && k > 0) {169         ans = (ans + (k+1)/2 % MOD * t[1].P[p&1]) % MOD;170 171         ans = (ans + k/2 % MOD * t[1].P[!(p&1)]) % MOD;172     }173     return ans;174 }175 176 int main()177 {178     freopen("in.txt", "r", stdin);179     //freopen("out.txt", "w", stdout);180     scanf("%d%*c", &cas);181     while(cas--)182     {183         LL a, b, c;184         gets(str);185         build(1, 1, n=strlen(str));186         for(int i =0 ; i < n; i ++)187             update(1, i + 1, str[i] - '0');188         scanf("%d", &q);189         while(q--) {190             scanf("%lld %lld %lld%*c", &a, &b, &c);191             if(a == 1) update(1, (int)b, (int)c);192             else {193                 LL rf = 0, lf = 0, lp = 0;194                 LL len = (c - b + 1), tmp = (len & 1 ^ 1);195                 rf = get_F( c - tmp, tmp );196                 if(b > 2) {197                     lf = get_F( b-2, tmp );198                     lp = get_P( b-2 );199                 }200                 //计算节结果201                 LL ans = ((rf - lf - (len + len%2) % MOD * lp) % MOD + MOD) % MOD;202                 printf("%lld\n", ans);203             }204         }205     }206     return 0;207 }
复制代码

 

 

 

 

3.

http://blog.csdn.net/wondezy/article/details/39164217

 

解题思路:对于询问[L,R]只有2种情况:1.在一段中 2.L,R分别在两段中,中间有若干段

第一步:

那么我们先处理原串P的情况。

在纸上写一下,容易发现,G(l,r)只有奇数项

且G(l,r)=a[l]*(r-l+1)+a[l+2]*(r-l-1)+....=sigma(a[x]*(r-x+1))=(r+1)*sigma(a[x])-sigma(a[x]*x)

那么,我们用树状数组维护a[x]和a[x]*x两个前缀和,修改就是单点修改。

但是,偶数项和并不是不用了,如果前面有一段是奇数,后面就要用到偶数项和

所以要维护奇数偶数项前缀的4个数组。


第二步:

我们已经知道原串P的任意一个区间的答案

如果有2个P长度的串,且P的长度为奇数,那么整个区间的答案就应该是第一个P的奇数项前缀和+第二个P的偶数项前缀和+第一个P的奇数项的偏移量(奇数项和*P)

我们在处理P的时候,就计算2*P长度的前缀和,这样对于中间的段都是以2*P分段的

我们设[L,R]被分成[ml,len],n个2*P,1或0个P,[1,mr]这几段,ml,mr为段内下标

[ml,len]的部分很好算就是原来的值加上偏移量

然后[1,mr]部分就是原来的值

设k为中间P的段数

n个2*P的部分为原来n个2*P的前缀和+偏移量

偏移量是2*P的前缀和(奇数项还是偶数项要看[L,len]的奇偶)*{sigma((k-2*b)*len+mr) ,b属于[1,n]}

如果还有剩下的P,再加上P的值和偏移量


第三步:

额,没了

#include <iostream>#include <cstdio>#include <cstring>#define maxn 100010#define ll long long#define mod 1000000007using namespace std;int t,ls;char s[maxn];int v[maxn<<1];ll a[2][maxn<<1],b[2][maxn<<1];void add(int t,int c,int d){    for(int x=c;x<=2*ls;x+=x&(-x)){        a[t][x]+=c*d,b[t][x]+=d;        a[t][x]%=mod,b[t][x]%=mod;    }}ll ask(ll *c,int x){    ll ret=0;    for(;x;x-=x&(-x)) ret+=c[x],ret%=mod;    return ret;}void read(){    scanf("%s",s+1);    ls=strlen(s+1);    for(int i=1;i<=ls;i++) v[i]=s[i]-'0';    for(int i=ls+1;i<=2*ls;i++) v[i]=v[i-ls];    memset(a,0,sizeof a);    memset(b,0,sizeof b);    for(int i=1;i<=2*ls;i++) add(i&1,i,v[i]);}ll calc(int t,ll ml,ll mr){    ll ret=((mr+1)*(ask(b[t],mr)-ask(b[t],ml-1)))%mod-(ask(a[t],mr)-ask(a[t],ml-1))%mod;    return ret%mod;}void solve(){    int q,T,x,d;    ll l,r;    scanf("%d",&q);    for(int i=0;i<q;i++){        scanf("%d",&T);        if(T==1){            scanf("%d%d",&x,&d);            add(x&1,x,-v[x]);            add(x&1,x,d);            add((x+ls)&1,x+ls,-v[x]);            add((x+ls)&1,x+ls,d);            v[x]=d;        }else{            scanf("%lld%lld",&l,&r);            ll kl=(l+ls-1)/ls,kr=(r+ls-1)/ls;            ll ml=l-(kl-1)*ls,mr=r-(kr-1)*ls;            ll ret=0;            ll kk=kr-kl-1,rr,sum;            if(kl==kr){                ret=calc(ml&1,ml,mr);            }else{                ret=calc(ml&1,ml,ls);                ret=(ret+(ask(b[ml&1],ls)-ask(b[ml&1],ml-1))*(ls*(kk%mod)%mod+mr)%mod)%mod;                sum=ask(b[1^((ls-ml+1)&1)],2*ls);                ll bb=kk/2;                if(bb>=1){                    bb%=mod;                    ret=(ret+calc(1^((ls-ml+1)&1),1,2*ls)*bb%mod)%mod;                    ret=(ret+sum*( (mr+kk%mod*ls%mod)*bb%mod-bb*(bb+1)%mod*ls%mod )%mod)%mod;                }                if(kk&1){                    ret=(ret+calc(1^((ls-ml+1)&1),1,ls))%mod;                    ret=(ret+ask(b[1^((ls-ml+1)&1)],ls)*mr%mod)%mod;                }                rr=ls-ml+1+ls*kk;                ret=(ret+calc(1^(rr&1),1,mr))%mod;            }            ret=(ret%mod+mod)%mod;            printf("%lld\n",ret);        }    }}int main(){    scanf("%d",&t);    for(int ca=1;ca<=t;ca++){        read();        solve();    }    return 0;}



 

0 0
原创粉丝点击