Description
我们定义一个非负整数是“好数”,当且仅当它符合以下条件之一:
1.这个数是0或1
2.所有小于这个数且与它互质的正整数可以排成一个等差数列例如,8就是一个好数,因为1,3,5,7排成了等差数列。
给出N个非负整数,然后进行如下三个操作:
1.询问区间[L,R]有多少个好数
2.将区间[L,R]内所有数对S取余(S≤1000000)
3.将第C个数更改为X
分析
首先我们应该找出什么数是好数,
通过打表就可以发现,所以的质数,2的次幂,以及6。
对于操作1和操作3,我们都可以用线段树轻松地维护。
关键是操作2。
如果一个区间的最大值都小于取模的数的话,很显然这次取模是没有意义的,可以不做处理。
可以证明一个数最多会被有效取模log次,
那么时间复杂度就可以保证了。
code
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define N 1000003
using namespace std;
int n,m,a[N],tr[N*4],mx[N*4],ss[N];
int x,y,z;
bool bz[N*10];
char ch;
void read(int &n)
{
n=0;
ch=getchar();
while((ch<'0' || ch>'9') && ch!='-')ch=getchar();
int w=1;
if(ch=='-')w=-1,ch=getchar();
while('0'<=ch && ch<='9')n=n*10+ch-'0',ch=getchar();
n*=w;
}
void make(int x,int l,int r)
{
if(l==r)
{
tr[x]=bz[a[l]];
mx[x]=a[l];
return;
}
int m=(l+r)/2;
make(x+x,l,m);
make(x+x+1,m+1,r);
tr[x]=tr[x+x]+tr[x+x+1];
mx[x]=max(mx[x+x],mx[x+x+1]);
}
int find(int x,int l,int r,int ll,int rr)
{
if(ll==l && rr==r)return tr[x];
int m=(l+r)/2;
if(rr<=m)return find(x+x,l,m,ll,rr);else
if(ll>m)return find(x+x+1,m+1,r,ll,rr);else
return find(x+x,l,m,ll,m)+find(x+x+1,m+1,r,m+1,rr);
}
void work(int x,int l,int r,int z)
{
if(mx[x]<z)return;
if(l==r)
{
mx[x]=mx[x]%z;
tr[x]=bz[mx[x]];
return;
}
int m=(l+r)/2;
work(x+x,l,m,z);
work(x+x+1,m+1,r,z);
tr[x]=tr[x+x]+tr[x+x+1];
mx[x]=max(mx[x+x],mx[x+x+1]);
}
void change(int x,int l,int r,int ll,int rr,int z)
{
if(mx[x]<z)return;
if(ll==l && rr==r)
{
work(x,l,r,z);
return;
}
int m=(l+r)/2;
if(rr<=m)change(x+x,l,m,ll,rr,z);else
if(ll>m)change(x+x+1,m+1,r,ll,rr,z);else
change(x+x,l,m,ll,m,z),change(x+x+1,m+1,r,m+1,rr,z);
tr[x]=tr[x+x]+tr[x+x+1];
mx[x]=max(mx[x+x],mx[x+x+1]);
}
void chan(int x,int y,int l,int r)
{
if(l==r)
{
mx[x]=z;
tr[x]=bz[mx[x]];
return;
}
int m=(l+r)/2;
if(y<=m)chan(x+x,y,l,m);
else chan(x+x+1,y,m+1,r);
tr[x]=tr[x+x]+tr[x+x+1];
mx[x]=max(mx[x+x],mx[x+x+1]);
}
void write(int x)
{
if(x>9) write(x/10);
putchar(x%10+'0');
}
int main()
{
memset(bz,1,sizeof(bz));
for(int i=2;i<=1000000;i++)
{
if(bz[i])
ss[++ss[0]]=i;
for(int j=1;j<=ss[0];j++)
{
if(ss[j]*i>1000000)break;
bz[ss[j]*i]=0;
if(i%ss[j]==0)break;
}
}
for(int i=2;i<=1000000;i=i*2)
bz[i]=1;
bz[6]=1;
freopen("good8.in","r",stdin);
freopen("good.out","w",stdout);
read(n);read(m);
for(int i=1;i<=n;i++)
read(a[i]);
make(1,1,n);
for(int k=1;k<=m;k++)
{
read(x);
read(y);
read(z);
if(x==1)write(find(1,1,n,y,z)),printf("\n");else
if(x==2)read(x),change(1,1,n,y,z,x);else
chan(1,y,1,n);
}
}