题目:戳这里
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;
}