[清華集訓2014]奇數國
阿新 • • 發佈:2018-12-11
[清華集訓2014]奇數國
luogu
UOJ
題意其實是讓單點修改,區間求\(\varphi\)
還保證分解之後只會有前60個質數
那麼用60個線段樹維護區間和即可
還有巧妙的做法是把60個質數是否存在壓在long long中線段樹維護
考試誰管那麼多...
然後BZOJ硬是T了...
#define ri register int #define ls x<<1,l,mid #define rs x<<1|1,mid+1,r #define ll long long #include<bits/stdc++.h> using namespace std; const int _=1e5+5,mod=19961993; inline int re(){ ri x=0,w=1;register char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*w; } int n=1e5,m; int prime[66]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281}; int val[66],js[66],s[60][_<<2]; inline void pu(ri x){ for(int i=0;i<60;i++)s[i][x]=s[i][x<<1]+s[i][x<<1|1]; } void bu(ri x,ri l,ri r){ if(l==r){s[1][x]=1;return;} ri mid=(l+r)>>1;bu(ls);bu(rs); s[1][x]=s[1][x<<1]+s[1][x<<1|1]; } void upd(ri x,ri l,ri r,ri k){ if(l==r){for(int i=0;i<60;i++)s[i][x]=val[i];return;}ri mid=(l+r)>>1; if(k<=mid)upd(ls,k);else upd(rs,k);pu(x); } void qsum(ri x,ri l,ri r,ri ql,ri qr){ if(ql<=l&&r<=qr){for(int i=0;i<60;i++)js[i]+=s[i][x];return;} ri mid=(l+r)>>1;if(ql<=mid)qsum(ls,ql,qr); if(qr>mid)qsum(rs,ql,qr); } inline void mul(ri&x,ri y){x=1ll*x*y%mod;} inline int ksm(ri x,ri y){ ri s=1; while(y){if(y&1)mul(s,x);mul(x,x);y>>=1;} return s; } int main(){ m=re(); bu(1,1,n); while(m--){ ri a=re(),b=re(),c=re(); if(a){ for(ri i=0;i<60;i++){ val[i]=0; while(c%prime[i]==0){ val[i]++;c/=prime[i]; } } upd(1,1,n,b); } else{ ri ans=1; memset(js,0,sizeof(js)); qsum(1,1,n,b,c); for(ri i=0;i<60;i++){ if(!js[i])continue; if(js[i]>1)mul(ans,ksm(prime[i],js[i]-1)); mul(ans,prime[i]-1); } printf("%d\n",ans); } } return 0; }