链接:https://www.nowcoder.com/acm/contest/163/H
来源:牛客网
题目描述
You have N integers A1, A2, ... , AN. You are asked to write a program to receive and execute two kinds of instructions:
1. C a b means performing Ai = (Ai2 mod 2018) for all Ai such that a ≤ i ≤ b.
2. Q a b means query the sum of Aa, Aa+1, ..., Ab. Note that the sum is not taken modulo 2018.
输入描述:
The first line of the input is T(1≤ T ≤ 20), which stands for the number of test cases you need to solve.
The first line of each test case contains N (1 ≤ N ≤ 50000).The second line contains N numbers, the initial values of A1, A2, ..., An. 0 ≤ Ai < 2018. The third line contains the number of operations Q (0 ≤ Q ≤ 50000). The following Q lines represents an operation having the format "C a b" or "Q a b", which has been described above. 1 ≤ a ≤ b ≤ N.
输出描述:
For each test case, print a line "Case #t:" (without quotes, t means the index of the test case) at the beginning.
You need to answer all Q commands in order. One answer in a line.
示例1
输入
1
8
17 239 17 239 50 234 478 43
10
Q 2 6
C 2 7
C 3 4
Q 4 7
C 5 8
Q 6 7
C 1 8
Q 2 5
Q 3 4
Q 1 8
输出
Case #1:
779
2507
952
6749
3486
9937
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int i=a;i<b;i++)
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
const int maxn=5e4+10;
int A[maxn];
//loop循环节里面对应的值
//th每个数字开始循环节的位置
//len每个数字循环节的长度
int loop[2200][20],th[2200],len[2200];
int lp[2200];
int vis[2200];
void init(){
for(int i=0;i<=2018;i++){
memset(vis,-1,sizeof(vis));
int tmp=i;
for(int j=0;;j++){
lp[j]=tmp;
if(vis[tmp]!=-1){
th[i]=vis[tmp];
len[i]=j-vis[tmp];
rep(k,0,len[i])loop[i][k]=lp[th[i]+k];
break;
}
else {
vis[tmp]=j;
tmp=tmp*tmp%2018;
}
}
// printf("i:%d th:%d len:%d\n",i,th[i],len[i]);
}
}
int lazy[maxn<<2],thsh[maxn<<2];
int res[maxn<<2],sum[maxn<<2][6];
void pushup(int o){
res[o]=res[ls(o)]+res[rs(o)];
thsh[o]=max(thsh[ls(o)],thsh[rs(o)]);
rep(i,0,6)sum[o][i]=sum[ls(o)][i]+sum[rs(o)][i];
}
void build(int l,int r,int o){
// printf("l:%d r:%d o:%d \n",l,r,o);
lazy[o]=0;
if(l==r){
// printf("o:%d len:%d A:%d\n",o,len[A[l]],A[l]);
thsh[o]=th[A[l]];
res[o]=A[l];
rep(i,0,6) sum[o][i]=loop[A[l]][i%len[A[l]]];
return;
}
int mid=(l+r)>>1;
build(l,mid,ls(o));
build(mid+1,r,rs(o));
pushup(o);
}
//如果说这棵子树上的值都已经过了阀值,我们只需要在树根上移移位置就好了,下面都是循环节了
int v[10];
void move(int o,int val){
rep(i,0,6) v[(i+6-val)%6]=sum[o][i];
rep(i,0,6) sum[o][i]=v[i];
res[o]=sum[o][0];
lazy[o]+=val;
lazy[o]%=6;
}
void pushdown(int o){
move(ls(o),lazy[o]);
move(rs(o),lazy[o]);
lazy[o]=0;
}
void update(int L,int R,int O,int y1,int y2){
//如果说下面的都已经超过了阀值,这样我们就可以直接移动数值了
if(!thsh[O]&&y1<=L&&R<=y2){
move(O,1);//已经过了阀值,我们可以直接在上面移动就好了
return;
}
//如果下面还有没到阀值的,就一直更新到叶子节点
if(L==R){
thsh[O]--;
res[O]=res[O]*res[O]%2018;
return;
}
if(lazy[O])pushdown(O);
int mid=(L+R)>>1;
if(y1<=mid)update(L,mid,ls(O),y1,y2);
if(y2>mid) update(mid+1,R,rs(O),y1,y2);
pushup(O);
}
int query(int l,int r,int o,int y1,int y2){
if(y1<=l&&r<=y2)return res[o];
if(lazy[o])pushdown(o);
int mid=(l+r)>>1;
int ans=0;
if(y1<=mid)ans+=query(l,mid,ls(o),y1,y2);
if(y2>mid) ans+=query(mid+1,r,rs(o),y1,y2);
return ans;
}
int main(){
init();
int T;
scanf("%d",&T);
rep(kase,0,T){
int n;
scanf("%d",&n);
rep(i,1,n+1)scanf("%d",&A[i]);
build(1,n,1);
printf("Case #%d:\n",kase+1);
int m;
scanf("%d",&m);
rep(i,0,m){
char ch;int l,r;
scanf(" %c %d %d",&ch,&l,&r);
if(ch=='Q') printf("%d\n",query(1,n,1,l,r));
else update(1,n,1,l,r);
}
}
return 0;
}