【bzoj3813】: 奇数国 数论-线段树-欧拉函数

【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 }
View Code

 

posted @ 2017-03-19 19:19  karl07  阅读(303)  评论(0编辑  收藏  举报