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