题目描述
众所周知,duxing201606得到了某知名数学家的真传,现在她有了无穷的力量.现在她面前有一个数组a,duxing201606打算施法,有两种魔法,
第一种:把[l,r]区间的每个数变成它的f函数,即a[i]=f(a[i]).
第二种:查询区间[l,r]中a[i]的和.
f(x)是1到x中与x互质的数的个数。f(1)=1.
输入
多组数据,请读到文件末尾.一个数n表示a的长度,(1<=n<=5e5).下一行n个数表示a[i],(1<=a[i]<=1e7).再下一行,一个q,表示执行的魔法个数.接下来q(1<=q<=5e5)行,先是操作种类,1表示魔法1,2表示魔法2,然后是区间l,r(1<=l<=r<=n)
输出
对于每个第二种操作,输出答案
样例输入
5
1 2 3 4 5
3
2 2 4
1 2 5
2 4 5
样例输出
9
6
这道题明显要使用欧拉函数,但我比赛时不会所以跳过了…
关于欧拉函数,这篇文章讲得比较好:
https://blog.csdn.net/liuzibujian/article/details/81086324
主要运用欧拉筛法,欧拉函数是积性函数等性质 o(n)求得欧拉函数
思路:线筛求phi,线段树维护a的区间和,由于phi最多执行log次就会变成1,直接暴力维护到叶子节点。判断一下是不是整个区间都是1,是的话就不用继续走了。
判断整个区间都是1的话就不用了更新了,然后直接普通的线段树就ok了
坑点:查询和树节点用 long long!!
#include<bits/stdc++.h>
#define fi first
#define se second
#define FOR(a) for(int i=0;i<a;i++)
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
typedef pair<P,int> LP;
const ll inf=0x3f3f3f3f;
const int N=5e5+10;
const ll mod=998244353;
map<string,ll> mp;
map<string ,int>ml;
const int mx=1e7+10;
int prime[mx];
ll tree[N<<2];
int phi[mx];
bool did[mx];
int n,m,x,t,tot=0;
void push_up(int rt)
{
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void build(int rt,int l,int r)
{
if(l==r)
{
scanf("%lld",&x);
tree[rt]=x;
return ;
}
int m=l+r >> 1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
push_up(rt);
}
void update(int ql, int qr,int rt,int l,int r)
{
if(tree[rt]==r-l+1) return;
if(l==r&&l>=ql&&r<=qr)
{
tree[rt]=phi[tree[rt]];
return ;
}
int m=l+r >> 1;
if(ql<=m) update(ql,qr,rt<<1,l,m);
if(qr>m) update(ql,qr,rt<<1|1,m+1,r);
push_up(rt);
}
ll query(int ql,int qr,int rt,int l,int r)
{
if(ql<=l&&qr>=r) return tree[rt];
int m= l+r >>1;
ll ans=0;
if(ql<=m) ans+=query(ql,qr,rt<<1,l,m);
if(qr>m) ans+=query(ql,qr,rt<<1|1,m+1,r);
return ans;
}
int main()
{
phi[1]=1;
int tot=0;
for(int i=2;i<=1e7;i++)
{
if(!did[i]) prime[++tot]=i,phi[i]=i-1;
for(int j=1;j<=tot&&i*prime[j]<=1e7;j++)
{
did[i*prime[j]]=1;
if(i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
}
//cout<<phi[1000000]<<endl;
while(scanf("%d",&n)!=EOF)
{
memset(tree,0,sizeof tree);
build(1,1,n);
int q;
scanf("%d",&q);
while(q--)
{
int t,l,r;
scanf("%d%d%d",&t,&l,&r);
if(t==1)
{
update(l,r,1,1,n);
}
else
{
printf("%lld\n",query(l,r,1,1,n));
}
}
}
}