【hdu5634】Rikka with Phi(线段树+欧拉函数)

xiaoxiao2021-02-28  111

Description

    Rikka and Yuta are interested in Phi function (which is known as Euler’s totient function).     Yuta gives Rikka an array A[1..n] of positive integers, then Yuta makes m queries.     There are three types of queries:         1 l r     Change A[i] into φ(A[i]), for all i∈[l,r].         2 l r x     Change A[i] into x, for all i∈[l,r].         3 l r     Sum up A[i], for all i∈[l,r].     Help Rikka by computing the results of queries of type 3.

Input

    The first line contains a number T(T100) ——The number of the testcases. And there are no more than 2 testcases with n>105     For each testcase, the first line contains two numbers n,m( n3105,m3105 )。     The second line contains n numbers A[i] .Each of the next m lines contains the description of the query.It is guaranteed that 1A[i]107 At any moment.

Output

    For each query of type 3, print one number which represents the answer.

Sample Input

1 10 10 56 90 33 70 91 69 41 22 77 45 1 3 9 1 1 10 3 3 8 2 5 6 74 1 1 8 3 1 9 1 2 10 1 4 9 2 8 8 69 3 3 9

Sample Output

80 122 86

I think

    题意:     1)一般线段树的加和操作     2)将节点值x改为 φ(x)     算法:线性筛欧拉函数+线段树     实现:作为一只第一次用到欧拉函数的蒟蒻,默默去膜了大佬们的筛法讲解,安利:几种常用的数学算法 线性筛欧拉函数     最后筛欧拉函数的代码就是这样啦

void Euler() { memset(isp,1,sizeof(isp)); p[0]=0,isp[1]=0,phi[1]=1; for(int i=2;i<sm;++i) { if(isp[i]) p[++p[0]]=i,phi[i]=i-1; for(int j=1;j<=p[0]&&i*p[j]<=sm;++j) { isp[i*p[j]]=0; if(i%p[j]==0) { phi[i*p[j]]=phi[i]*p[j];break;} phi[i*p[j]]=phi[i]*(p[j]-1); } } }

    而我们知道,对于一个数n反复取欧拉函数,它可以在 log(n) 的时间内最终变为1,如果有连着一大段一大段的1不是我们喜闻乐见的吗?——就可以把它们合作一个区间更新啦,因此在执行操作1时,更新需要满足的条件不再仅是ll<=l&&r<=rr,还需要再设一个标记表示是否整个区间均为1,同时满足k[i]==1即可,否则继续递归到满足要求为止。

Code

#include<cstdio> #include<cstring> using namespace std; typedef long long LL; const LL sm = 1e7+10; const LL mx = 1200000+50; LL n,m,T; LL v,s[mx],k[mx]; int isp[sm],phi[sm],p[700000]; char ch; template <typename T> void read(T &x) { x=0,ch=getchar(); while(ch>'9'||ch<'0') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); } void Euler() { memset(isp,1,sizeof(isp)); p[0]=0,isp[1]=0,phi[1]=1; for(int i=2;i<sm;++i) { if(isp[i]) { p[++p[0]]=i; phi[i]=i-1; } for(int j=1;j<=p[0]&&i*p[j]<=sm;++j) { isp[i*p[j]]=0; if(i%p[j]==0) { phi[i*p[j]]=phi[i]*p[j]; break; } phi[i*p[j]]=phi[i]*(p[j]-1); } } } void pushup(LL i,LL l,LL r) { LL ls=i<<1,rs=i<<1|1; s[i]=s[ls]+s[rs]; if(k[ls]==k[rs]) k[i]=k[ls]; else k[i]=0; } void pushdown(LL i,LL l,LL r) { LL m=(l+r)>>1,ls=i<<1,rs=i<<1|1; k[ls]=k[rs]=k[i]; s[ls]=(m-l+1)*k[ls]; s[rs]=(r-m)*k[rs]; } void build(LL i,LL l,LL r) { s[i]=k[i]=0; if(l==r) { read(v),s[i]=k[i]=v;return; } LL m=(l+r)>>1; build(i<<1,l,m); build(i<<1|1,m+1,r); pushup(i,l,r); } void modify(LL i,LL l,LL r,LL ll,LL rr,LL val) { if(ll<=l&&r<=rr) { s[i]=(r-l+1)*val,k[i]=val; return ; } if(k[i])pushdown(i,l,r); LL m=(l+r)>>1; if(ll<=m) modify(i<<1,l,m,ll,rr,val); if(rr> m) modify(i<<1|1,m+1,r,ll,rr,val); pushup(i,l,r); } void euler(LL i,LL l,LL r,LL ll,LL rr) { if(k[i]&&ll<=l&&r<=rr) { k[i]=phi[k[i]],s[i]=1ll*k[i]*(r-l+1); return; } if(l==r)return; if(k[i]) pushdown(i,l,r); LL m=(l+r)>>1; if(ll<=m) euler(i<<1,l,m,ll,rr); if(rr> m) euler(i<<1|1,m+1,r,ll,rr); pushup(i,l,r); } LL query(LL i,LL l,LL r,LL ll,LL rr) { if(l>r)return 0; if(ll<=l&&r<=rr) return s[i]; if(k[i]) pushdown(i,l,r); LL m=(l+r)>>1; LL ans=0; if(ll<=m) ans+=query(i<<1,l,m,ll,rr); if(rr> m) ans+=query(i<<1|1,m+1,r,ll,rr); pushup(i,l,r); return ans; } int main() { Euler(); read(T); LL ind,ll,rr,val; while(T--) { read(n),read(m); build(1,1,n); for(LL i=1;i<=m;++i) { read(ind),read(ll),read(rr); if(ind==2) read(val),modify(1,1,n,ll,rr,val); else if(ind==1) euler(1,1,n,ll,rr); else printf("%lld\n",query(1,1,n,ll,rr)); } } return 0; }
转载请注明原文地址: https://www.6miu.com/read-82079.html

最新回复(0)