大意是有n段路,每一段路有个值a,通过每一端路需要1s,如果通过这一段路时刻t为a的倍数,则需要等待1s再走,也就是需要2s通过。
比较头疼的就是相邻两个数之间会因为数字不同制约,一开始想a的范围是2-6,处理这几个数字互相之间的关系,还是想岔了。
正解应当是开60个线段树,因为2-6的LCM是60,也就是所有数字模2-6,结果的循环节长度为60。所以如果从i到j,开始时刻如果为0,则答案一定与开始时刻为60相同。
第x个线段树某个节点范围如果是i和j,维护的便是开始时刻模60为x的情况下,从i到j+1需要的时间。
写的时候按照这个处理节点信息合并与查询即可。
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 #include <string> 5 #include <cstring> 6 #include <cstdio> 7 #include <cmath> 8 #include <cstdlib> 9 #include <queue> 10 #include <stack> 11 #include <map> 12 #include <set> 13 14 using namespace std; 15 16 const int N=1e5+10; 17 const int M=60; 18 int v[N<<2][M]; 19 20 void up(int rt) { 21 for (int i=0;i<M;i++) { 22 v[rt][i]=v[rt<<1][i]+v[rt<<1|1][(i+v[rt<<1][i])%M]; 23 } 24 } 25 void build(int l,int r,int rt) { 26 if (l==r) { 27 int a; 28 scanf("%d",&a); 29 for (int i=0;i<M;i++) 30 v[rt][i]=1+(i%a==0); 31 return; 32 } 33 int m=(l+r)>>1; 34 build(l,m,rt<<1); 35 build(m+1,r,rt<<1|1); 36 up(rt); 37 } 38 void update(int p,int a,int l,int r,int rt) { 39 if (l==r) { 40 for (int i=0;i<M;i++) 41 v[rt][i]=1+(i%a==0); 42 return; 43 } 44 int m=(l+r)>>1; 45 if (p<=m) 46 update(p,a,l,m,rt<<1); 47 else 48 update(p,a,m+1,r,rt<<1|1); 49 up(rt); 50 } 51 int ask(int L,int R,int l,int r,int rt,int p) { 52 if (L<=l&&r<=R) { 53 return v[rt][p]; 54 } 55 int ret=0; 56 int m=(l+r)>>1; 57 if (L<=m) ret+=ask(L,R,l,m,rt<<1,p); 58 if (R>m) ret+=ask(L,R,m+1,r,rt<<1|1,(p+ret)%M); 59 return ret; 60 } 61 int main () { 62 int n; 63 scanf("%d",&n); 64 build(1,n,1); 65 int Q; 66 scanf("%d",&Q); 67 while (Q--) { 68 char s[5]; 69 int x,y; 70 scanf("%s %d %d",s,&x,&y); 71 if (s[0]=='C') 72 update(x,y,1,n,1); 73 else 74 printf("%d\n",ask(x,y-1,1,n,1,0)); 75 } 76 return 0; 77 }