【bzoj3813】: 奇数国 数论-线段树-欧拉函数
题意:给定一个序列,每个元素可以分解为最小的60个素数的形式。(x=p1^k1*p2^k2*......p60^k60)(p1=2,p2=3,…,p60=281)
支持单点修改,查询一段区间的积的欧拉函数 mod 19961993(是一个质数)。
线段树维护区间积x,bitset b[i]记录第i个素数是否存在。
预处理inv[i]=(p[i]-1)/p[i] mod 19961993
ans=x*inv[i] (b[i]==1)
1 /* http://www.cnblogs.com/karl07/ */ 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <algorithm> 7 #include <bitset> 8 #define LL long long 9 using namespace std; 10 const int P=19961993; 11 const int N=100000; 12 const int prime[60]={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}; 13 const int inv[60]={9980997,13307996,7984798,11406854,14517814,18426456,9393880,5253157,16490343,8260136,2575742,18343454,3895024,17640832,1698894,3013132,7443456,4581442,9236147,18275065,6562848,2779519,7936697,4037258,6379607,19566707,13566404,4104336,3662752,13602421,16661192,1219054,13259427,9047523,3751248,8196316,14621843,1714528,12192356,11884887,8029406,13455046,17976246,13342473,14084859,15548287,10217514,9846724,5364237,3486812,1627803,14950615,1076789,12406658,19340609,8652728,7791857,7955334,1657495,8808852}; 14 15 struct data{ 16 bitset <70> b; 17 LL x; 18 data (LL x=1){ 19 if (x==1){ 20 this->x=1; 21 this->b.reset(); 22 }else{ 23 this->x=x; 24 for (int i=0;i<60;i++){ 25 if (!(x%prime[i])) this->b[i]=1; 26 } 27 } 28 } 29 }; 30 data operator + (const data &a,const data &b){ 31 data c; 32 c.b=a.b|b.b; c.x=a.x*b.x%P; 33 return c; 34 } 35 struct seg{ 36 data d; 37 seg *ls,*rs; 38 } t[N*2+5]; 39 40 seg *root,*NEW=t; 41 seg *new1(){ return ++NEW;} 42 43 #define mid (ll+rr)/2 44 void build(seg *p,int ll,int rr){ 45 if (ll==rr){ 46 p->d=data(3); 47 }else{ 48 build(p->ls=new1(),ll,mid); 49 build(p->rs=new1(),mid+1,rr); 50 p->d=p->ls->d+p->rs->d; 51 } 52 } 53 54 void modify(seg *p,int ll,int rr,int x,data d){ 55 if (ll==rr){ 56 p->d=d; 57 }else{ 58 if (x<=mid) modify(p->ls,ll,mid,x,d); 59 if (x>mid) modify(p->rs,mid+1,rr,x,d); 60 p->d=p->ls->d+p->rs->d; 61 } 62 } 63 64 data query(seg *p,int ll,int rr,int l,int r){ 65 data ans=data(1); 66 if (l<=ll && r>=rr){ 67 ans=ans+p->d; 68 }else{ 69 if (l<=mid) ans=ans+query(p->ls,ll,mid,l,r); 70 if (r>mid) ans=ans+query(p->rs,mid+1,rr,l,r); 71 } 72 return ans; 73 } 74 75 LL cal(data d){ 76 LL ans=d.x; 77 for (int i=0;i<60;i++){ 78 if (d.b[i]==1){ 79 ans=ans*inv[i]%P; 80 } 81 } 82 return ans; 83 } 84 85 int n; 86 87 int main(){ 88 scanf("%d",&n); 89 build(root=new1(),1,N); 90 for (int i=1;i<=n;i++){ 91 int a,b,c; 92 scanf("%d%d%d",&a,&b,&c); 93 if (a==0){ 94 printf("%lld\n",cal(query(root,1,N,b,c))); 95 }else{ 96 modify(root,1,N,b,data(c)); 97 } 98 } 99 return 0; 100 }