1. 程式人生 > >2018.10.25【NOIP練習】ZUA球困難綜合徵(線段樹)(CRT)

2018.10.25【NOIP練習】ZUA球困難綜合徵(線段樹)(CRT)

傳送門

解析:

首先,這天坑的出題人。。。

思路肯定是線段樹維護區間運算結果,但是兩萬多的模數怎麼維護?

這奇怪的光速。。。光速不是299792458m/s299792458m/s嗎?怎麼會變成2939329393

是的模數是這道題解決的關鍵,因為29393=7×13×17×1929393=7\times 13\times 17\times 19

所以我們只需要線段樹維護這四個模數的結果,再用CRTCRT合併一下就行了。

雖然說更新的常數有點大(40多),但是已經比兩萬多不知道好到哪裡去了。

程式碼:

#include<bits/stdc++.h>
using namespace std; #define ll long long #define re register #define gc getchar #define pc putchar #define cs const inline int getint(){ re int num; re char c; while(!isdigit(c=gc()));num=c^48; while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48); return num; } inline void outint(
int a){ static char ch[13]; if(a==0)pc('0'); while(a)ch[++ch[0]]=a-a/10*10,a/=10; while(ch[0])pc(ch[ch[0]--]^48); } inline int quickpow(int a,int b,int mod,int ans=1){ for(;b;b>>=1,a=a*a%mod)if(b&1)ans=ans*a%mod; return ans; } inline char getop(){ re char c; while((c=gc())!='^'&&c!=
'*'&&c!='+'); return c; } cs int M=29393;//7*13*17*19 cs int N=100005; struct node{int remain[4][20];}t[N<<1],Ans; cs int mod[4]={7,13,17,19}; int remain[4]; int inv[4][20]; inline int CRT(){ int ans=0; for(int re i=0;i<4;++i) ans=(ans+(M/mod[i])*inv[i][(M/mod[i])%mod[i]]%M*remain[i]%M)%M; return ans; } inline int solve(char op,int val,int now,int mod){ switch(op){ case '+':return (val+now)%mod; case '*':return val*now%mod; case '^':return quickpow(now,val,mod); } } inline void pushup(int k){ for(int re i=0;i<4;++i){ for(int re j=0;j<mod[i];++j) t[k].remain[i][j]=t[k<<1|1].remain[i][t[k<<1].remain[i][j]]; } } inline void build(int k,int l,int r){ if(l==r){ char op=getop(); int val=getint(); for(int re i=0;i<4;++i){ for(int re j=0;j<mod[i];++j) t[k].remain[i][j]=solve(op,val,j,mod[i]); } return ; } int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); pushup(k); } inline void update(int k,int l,int r,cs int &pos){ if(l==r){ char op=getop(); int val=getint(); for(int re i=0;i<4;++i){ for(int re j=0;j<mod[i];++j) t[k].remain[i][j]=solve(op,val,j,mod[i]); } return ; } int mid=(l+r)>>1; if(pos<=mid)update(k<<1,l,mid,pos); else update(k<<1|1,mid+1,r,pos); pushup(k); } inline void solve(int x){ for(int re i=0;i<4;++i)remain[i]=t[1].remain[i][x%mod[i]]; outint(CRT()),pc('\n'); } int n,m; signed main(){ for(int re i=0;i<4;++i)inv[i][0]=inv[i][1]=1; for(int re j=0;j<4;++j){ for(int re i=2;i<mod[j];++i){ inv[j][i]=(mod[j]-mod[j]/i)*inv[j][mod[j]%i]%mod[j]; } } n=getint(); m=getint(); build(1,1,n); while(m--){ int op=getint(),x=getint(); switch(op){ case 1:{solve(x);break;} case 2:{update(1,1,n,x);break;} } } return 0; }