额
神仙题
感觉就是一个暴力啊
线段树维护的是一个类似于键值线段树的东西?
每个叶子节点才表示一个操作
而在PushUp的时候合并答案
这个咋合并?
暴力合并。我们记录下当前模意义下所有的答案
然后暴力合并
于是查答案是O1的
然后明显开不下空间
但是考虑到模数的特殊性
于是拆成小质数CRT一下就好了
很完美的把暴力+线段树合并的真实意义+数学结合起来的一道题
#include<bits/stdc++.h>
using namespace std;
#define lc (p<<1)
#define rc (p<<1|1)
const int N=50010;
int Mod[4]={7,13,17,19};
const int M=29393;
int n,m;
int P[4][20][M+1];
void Init(){
for(int i=0;i<=3;i++){
for(int j=0;j<Mod[i];j++){
P[i][j][0]=1;
for(int k=1;k<M;k++){
P[i][j][k]=P[i][j][k-1]*j%Mod[i];
}
}
}
}
struct Segment_Tree{
int T[N<<2][4][20];
inline void Clear(){
memset(T,0,sizeof(T));
}
inline void PushUp(int p){
for(int i=0;i<=3;i++){
for(int j=0;j<Mod[i];j++)
T[p][i][j]=T[rc][i][T[lc][i][j]];
}
}
inline void PushNow(int p,char opt,int x){
for(int i=0;i<=3;i++){
for(int j=0;j<Mod[i];j++){
if(opt=='+'){
T[p][i][j]=(j+x)%Mod[i];
}
if(opt=='*'){
T[p][i][j]=(j*x)%Mod[i];
}
if(opt=='^'){
T[p][i][j]=P[i][j][x];
}
}
}
}
inline void build(int p,int l,int r){
if(l==r){
char opt;
int x;
scanf("%c%d",&opt,&x);
// cout<<opt<<" "<<x<<'\n';
getchar();
PushNow(p,opt,x);
return;
}
int mid=(l+r)/2;
build(lc,l,mid);
build(rc,mid+1,r);
PushUp(p);
}
inline void Update(int p,int l,int r,int pos,char opt,int x){
if(l==r){
PushNow(p,opt,x);
return;
}
int mid=(l+r)/2;
if(pos<=mid)Update(lc,l,mid,pos,opt,x);
else Update(rc,mid+1,r,pos,opt,x);
PushUp(p);
}
}Tree;
int quick_pow(int x,int k,int Mod){
int ret=1;
while(k){
if(k%2==1){
ret=ret*x%Mod;
}
k/=2;
x=x*x%Mod;
}
return ret;
}
void CRT(int x){
int ans=0;
for(int i=0;i<=3;i++){
ans+=Tree.T[1][i][x%Mod[i]]*quick_pow(M/Mod[i],Mod[i]-2,Mod[i])%M*(M/Mod[i])%M;
}
cout<<ans%M<<'\n';
}
void Solve(){
scanf("%d%d",&n,&m);getchar();
Tree.Clear();
Tree.build(1,1,n);
for(int i=1;i<=m;i++){
int flag;
scanf("%d",&flag);
// cout<<i<<" "<<flag<<'\n';
if(flag==1){
int x;
scanf("%d",&x);
CRT(x);
// cout<<"hello";
}
else{
int x;
int Id;
char opt;
scanf("%d",&Id);
getchar();
scanf("%c%d",&opt,&x);
Tree.Update(1,1,n,Id,opt,x);
}
}
}
int main(){
// freopen("test.in","r",stdin);
int Cas,Id=0;
Init();
scanf("%d",&Cas);
while(Cas--){
cout<<"Case #"<<++Id<<":"<<'\n';
Solve();
}
}