【FJWC2017】交错和查询 [线段树]
交错和查询
Time Limit: 10 Sec Memory Limit: 256 MBDescription
无限循环数字串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 }