【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\n", (s64)(A * (y%MOD+1) % MOD - A_i + MOD) % MOD);
189 }
190 }
191
192 }
View Code

 

智能推荐

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告