【FJWC2017】交错和查询 [线段树]

交错和查询

Time Limit: 10 Sec  Memory Limit: 256 MB

Description

  无限循环数字串S由长度为n的循环节s构成。设s为12345(n=5),则数字串S为123451234512345…
  设Si为S的第i位数字,在上面的例子中,S1=1,S2=2,S6=1。
  设S的一个子串S[l,r]的交错和为sum(l,r):
  sum(l,r) = Sl - S1+1 + Sl+2- Sl+3 + … + (-1)r-lSr
  如sum(2,7) = 2 - 3 + 4 - 5 + 1 - 2 = -3
  现给定循环节s,要求支持两种操作:
  1 pos digit:修改循环节s上的某一位,即将spos改为digit。
  2 l r:求S[l,r]内所有子串的交错和的和,即输出ans对10^9+7的模。

Input

  第一行一个整数n,表示循环节s的长度。
  第二行一个长度为n的数字串,表示循环节s。
  第三行一个整数m,表示操作次数。
  以下m行,每行3个整数。
  若第一个数为1,表示是修改操作1 pos digit。
  若第一个数为2,表示是询问操作2 l r。

Output

  对于每个询问操作输出一行,表示答案。

Sample Input 

  5
  12345
  5
  2 1 5
  2 6 10
  1 3 5
  2 1 5
  2 1 6

Sample Output

  19
  19
  25
  36

HINT

  对于10%的数据点,n, m <= 50;
  对于20%的数据点,n, m <=1000;
  对于40%的数据点,1 <= l<= r <= n;
  对于100%的数据点,n, m <=200000;1 <= l <= r <= 1018;1 <= pos <= n;0 <= digit <= 9;

Main idea

  给定两种操作:1.修改循环节上的某一位;2.询问[l,r]的所有子串和。 

Solution

  首先轻易地找到了规律,发现对于区间[l,r],只有奇数位置上的值会对答案产生影响,并且:,然后我们拆开式子得到:。现在考虑如何用一个数据结构来维护这个Ans,这里采用线段树

  我们分几步来实现:

  第一步:
  我们先考虑l,r在一个循环节内的情况。显然对于线段树上的每个节点维护五个信息:len, odd.val, odd.val_i, eve.val, eve.val_i分别表示区间长度、奇数位置的和、奇数位置*i的和、偶数位置的和、偶数位置*i的和,那么我们上传合并线段树的时候判断一下区间长度的奇偶即可。举个例子:比如现在左区间长度为3,要更新奇数位置的值,就是左区间的奇数位置和 加上 右区间的偶数位置和,我们重载运算符判断一下即可。这样操作我们就可以得到Σai以及Σai*i。

  第二步:
  (1)  我们再来考虑一下l,r不在一个循环节内的情况。显然我们可以将区间拆成三部分:左段、中段、右段,其中中段是包含所有的1-n的整体,而左段和右段则是~n或者1~的一部分

  (2)  然后我们显然可以很轻易地通过计算一下x,y的间隔块数以及若干信息来算出Σai。

  (3)  那么式子后面的Σai*i怎么办呢?我们发现:我们将序列分为若干段,显然每一段增加的值是一样的,那么我们就可以将Σai*i(这里的i是实际位置)拆成:Σai*i (在一个循环节中的位置) + Σai*(所在块数-1)*n。

  (4)  然后我们中段块数一定不为1,要怎么办呢?举个例子,比如循环节长度为10,我们要求2~4段的Σ,那么显然就是Σai*n*(i+1+2),惊讶地发现中间的一个等差数列,那么我们要乘的就是一个等差数列的和了。

  (5)  然后三段中到底是统计奇数位置的和还是统计偶数位置的和呢?发现较难处理,于是我们可以将原序列*2(拓展一倍),发现如果x是奇数,那么就加上左段的奇数位置,中段右段的奇数位置,否则加上左段的奇数位置,以及中段右段的偶数位置。

  这样我们就解决了问题,具体问题还是参见代码啦。

Code

  1 #include<iostream>     
  2 #include<string>     
  3 #include<algorithm>     
  4 #include<cstdio>     
  5 #include<cstring>     
  6 #include<cstdlib>     
  7 #include<cmath>     
  8 #include<map>   
  9 using namespace std;   
 10 typedef long long s64;
 11 
 12 const int ONE=200001;
 13 const s64 Niyu=5e8+4;
 14 const int MOD=1e9+7;
 15 
 16 int n,T;
 17 int a[ONE*2];
 18 char ch[ONE];
 19 int Q;
 20 s64 x,y;
 21 s64 x_orig,y_orig,x_bloc,y_bloc,diff;
 22 s64 A,A_i;
 23 
 24 struct power
 25 {
 26         int len;
 27         
 28         struct point
 29         {
 30             s64 val,val_i;
 31             friend point operator +(point a,point b)
 32             {
 33                 a.val=(a.val + b.val)%MOD;
 34                 a.val_i=(a.val_i + b.val_i) % MOD;
 35                 return a; 
 36             }
 37         }odd,eve;
 38         
 39         friend power operator +(power a,power b)
 40         {
 41             power c;
 42             c.len = a.len+b.len;
 43             if(a.len%2)
 44             {
 45                 c.odd = a.odd+b.eve;
 46                 c.eve = a.eve+b.odd;
 47             }
 48             else
 49             {
 50                 c.odd = a.odd+b.odd;
 51                 c.eve = a.eve+b.eve;
 52             }
 53             return c;
 54         }
 55 }Node[ONE*10],ZERO;
 56 
 57 s64 get()     
 58 {     
 59         s64 res=1,Q=1;char c;     
 60         while( (c=getchar())<48 || c>57 )  
 61         if(c=='-')Q=-1;  
 62         if(Q) res=c-48;      
 63         while( (c=getchar())>=48 && c<=57 )     
 64         res=res*10+c-48;     
 65         return res*Q;     
 66 }
 67 
 68 void Build(int i,int l,int r)
 69 {
 70         if(l==r)
 71         {
 72             Node[i].len = 1;
 73             Node[i].odd.val = a[l];
 74             Node[i].odd.val_i = a[l]*l % MOD;
 75             return;
 76         }
 77         
 78         int mid=(l+r)/2;
 79         Build(i*2,l,mid); Build(i*2+1,mid+1,r);
 80         
 81         Node[i] = Node[i*2] + Node[i*2+1];
 82 }
 83 
 84 void Update(int i,int l,int r,int L,int x)
 85 {
 86         if(L==l && l==r)
 87         {
 88             Node[i].odd.val = x;
 89             Node[i].odd.val_i = x*l % MOD;
 90             Node[i].eve.val = Node[i].eve.val_i = 0;
 91             return;
 92         }
 93         
 94         int mid=(l+r)/2;
 95         if(L<=mid) Update(i*2,l,mid,L,x);
 96         else Update(i*2+1,mid+1,r,L,x);
 97         
 98         Node[i] = Node[i*2] + Node[i*2+1];
 99 }
100 
101 power Query(int i,int l,int r,int L,int R)
102 {
103         if(L>R) return ZERO;
104         if(L<=l && r<=R) return Node[i];
105         
106         int mid=(l+r)/2;
107         if(R<=mid) return Query(i*2,l,mid,L,R);
108         if(mid+1<=L) return Query(i*2+1,mid+1,r,L,R);
109         return Query(i*2,l,mid,L,R) + Query(i*2+1,mid+1,r,L,R);
110 }
111 
112 s64 HE(s64 a,s64 b)
113 {
114         a--;    b--;
115         if(a==b) return 1;
116         if(a>b) return 0;
117         s64 x=(b-a+1) % MOD;
118         return (s64)(a+b)%MOD*x%MOD * Niyu % MOD;
119 }
120 
121 int main()
122 {
123         ZERO.len=1; ZERO.odd.val=ZERO.odd.val_i=ZERO.eve.val=ZERO.eve.val_i=0;
124         
125         n=get();
126         scanf("%s",ch+1);
127         for(int i=1;i<=n;i++) a[i]=ch[i]-'0';
128         for(int i=1;i<=n;i++) a[i+n]=a[i];
129         n*=2;    Build(1,1,n);
130         
131         T=get();
132         while(T--)
133         {
134             Q=get();
135             if(Q==1)
136             {
137                 x=get();    y=get();
138                 Update(1,1,n,x,y);
139                 Update(1,1,n,x+n/2,y);
140             }
141             else
142             {
143                 x=get();    y=get();
144                 x_orig=(x-1)%n+1;    y_orig=(y-1)%n+1;
145                 x_bloc=(x-1)/n+1;    y_bloc=(y-1)/n+1;
146                 
147                 diff = y_bloc-x_bloc-1;    diff%=MOD;
148                 if(diff!=-1)
149                 {
150                     if(x%2)
151                     {
152                         power res_l = Query(1,1,n, x_orig,n);
153                         power res_r = Query(1,1,n, 1,y_orig);
154                         power res_mid = Query(1,1,n, 1,n);
155                         
156                         A =( res_l.odd.val + res_r.odd.val + res_mid.odd.val * diff % MOD ) % MOD;
157                         A_i=0;
158                         
159                         A_i += (res_l.odd.val_i + (s64)res_l.odd.val * (x_bloc-1)%MOD * n % MOD)%MOD; A_i%=MOD;
160                         A_i += (res_r.odd.val_i + (s64)res_r.odd.val * (y_bloc-1)%MOD * n % MOD)%MOD; A_i%=MOD;
161                         
162                         A_i += (diff*res_mid.odd.val_i%MOD + (s64)res_mid.odd.val * n % MOD * HE(x_bloc+1,y_bloc-1)%MOD)%MOD;
163                         A_i%=MOD;
164                     }
165                     else
166                     {
167                         power res_l = Query(1,1,n, x_orig,n);
168                         power res_r = Query(1,1,n, 2,y_orig);
169                         power res_mid = Query(1,1,n, 2,n);
170                         
171                         A =( res_l.odd.val + res_r.odd.val + res_mid.odd.val * diff % MOD ) % MOD;
172                         A_i=0;
173                         
174                         A_i += (res_l.odd.val_i + (s64)res_l.odd.val * (x_bloc-1)%MOD * n % MOD)%MOD; A_i%=MOD;
175                         A_i += (res_r.odd.val_i + (s64)res_r.odd.val * (y_bloc-1)%MOD * n % MOD)%MOD; A_i%=MOD;
176                         
177                         A_i += (diff*res_mid.odd.val_i%MOD + (s64)res_mid.odd.val * n % MOD * HE(x_bloc+1,y_bloc-1)%MOD)%MOD;
178                         A_i%=MOD;
179                     }
180                 }
181                 else
182                 {
183                     power res = Query(1,1,n, x_orig,y_orig);
184                     A = res.odd.val;
185                     A_i=0;
186                     A_i += (s64)(res.odd.val_i + A * (x_bloc-1)%MOD * n % MOD) % MOD; A_i%=MOD;
187                 }
188                 printf("%lld
", (s64)(A * (y%MOD+1) % MOD - A_i + MOD) % MOD);
189             }
190         }
191         
192 }
View Code
原文地址:https://www.cnblogs.com/BearChild/p/6440737.html