題目:戳這裏
Solution
線段樹每個節點維護60個值,分別是走到該區間左端時時間爲i時該區間所用的時間,因爲題目中2<=y<=6,2到6的最小公倍數爲60,則走過的時間在判斷是否堵車是可以mod 60。
代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100010;
struct Data{
int t[60];
Data(){memset(t,0,sizeof t);}
};
struct Segment_Tree{
#define lc x<<1
#define rc x<<1|1
int L[maxn<<2],R[maxn<<2];
Data res[maxn<<2];
void update(int x){
for(int i=0;i<60;i++)
res[x].t[i]=res[lc].t[i]+res[rc].t[(i+res[lc].t[i])%60];
}
void Build(int x,int *a,int l,int r){
if((L[x]=l)==(R[x]=r)){
for(int i=0;i<60;i++)
if(i%a[l])res[x].t[i]=1;
else res[x].t[i]=2;
return;
}
int mid=(l+r)>>1;
Build(lc,a,l,mid);Build(rc,a,mid+1,r);
update(x);
}
void Change(int x,int pos,int val){
if(L[x]==R[x]){
for(int i=0;i<60;i++)
if(i%val)res[x].t[i]=1;
else res[x].t[i]=2;
return;
}
int mid=(L[x]+R[x])>>1;
if(pos<=mid)Change(lc,pos,val);
else Change(rc,pos,val);
update(x);
}
Data Query(int x,int l,int r){
if(L[x]>=l&&R[x]<=r)return res[x];
int mid=(L[x]+R[x])>>1;
Data temp,ls,rs;
if(l<=mid&&r>mid){
ls=Query(lc,l,r);rs=Query(rc,l,r);
for(int i=0;i<60;i++)
temp.t[i]=ls.t[i]+rs.t[(i+ls.t[i])%60];
return temp;
}
else if(l<=mid)return Query(lc,l,r);
else return Query(rc,l,r);
}
}tree;
int n,m,a[maxn];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
tree.Build(1,a,1,n);
scanf("%d",&m);
while(m--){
char opt[5];int x,y;
scanf("%s%d%d",opt,&x,&y);
if(opt[0]=='A')printf("%d\n",tree.Query(1,x,y-1).t[0]);
else if(opt[0]=='C')tree.Change(1,x,y);
}
return 0;
}