3813: 奇数国|树状数组|欧拉函数

来源:互联网 发布:java报表开发工具 编辑:程序博客网 时间:2024/06/06 09:21

题目显然让求

φi=lrai

可以用线段树维护一下乘积然后求逆元再求欧拉函数,用压位的方法可以缩小60倍的常数。考虑一下树状数组的做法,因为只有60个质因子,所以可以开60个树状数组维护每一个质因子,最初维护了前缀的乘积然后T飞了。因为乘法比起加法还是比较慢的所以可以维护一个前缀的指数和,这样就可以在BZOJ成功卡进最后一页QAQ,然而UOJ的Extra Test还是过不了(应该是我写的代码太丑的原因吧。。

#include<algorithm>#include<iostream>#include<cstdlib>#include<cstring>#include<cstdio>#include<vector>#include<cmath>#include<queue>#include<set>#include<map>#define ll long long#define mod 19961993#define N 100001using namespace std;int sc(){    int i=0,f=1; char c=getchar();    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}    while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();    return i*f;}int prime[66],inv[66],b[300],top;int tr[61][N],n,Q,a[N],flag;ll cal(ll x,ll y){    ll ans=1;    for(;y;x=x*x%mod,y>>=1)        if(y&1)ans=ans*x%mod;    return ans;}void change(int x,int y,ll v){    for(;y<N;y+=y&-y)tr[x][y]+=v;}ll ask(int  x,int y){    ll ans=0;    for(;y;y-=y&-y)ans+=tr[x][y];    return ans;}void solve(int p,ll x,int i,int f){    ll now=0;    while(x%prime[i]==0)x/=prime[i],now++;    change(i,p,f*now);}int main(){    for(int i=2;i<=281;i++)        if(!b[i])        {            prime[++top]=i;inv[top]=cal(prime[top],mod-2);            for(int j=2*i;j<=281;j+=i)b[j]=1;        }    for(int i=1;i<N;i++)change(2,i,1),a[i]=3;    Q=sc();    while(Q--)    {        if(sc())        {            int x=sc(),y=sc();            for(int i=1;i<=60;i++)            {                if(a[x]%prime[i]==0) solve(x,a[x],i,-1);                if(y%prime[i]==0) solve(x,y,i,1);            }            a[x]=y;        }        else        {            int l=sc(),r=sc();            ll ans=1;            for(int i=1;i<=60;i++)            {                ll res=ask(i,r)-ask(i,l-1);                if(res)                    ans=ans*cal(prime[i],res-1)*(prime[i]-1)%mod;            }            printf("%d\n",ans);        }    }    return 0;}
0 0