【题解】
查询很容易做到O(logN)
修改时注意:
第i位上的数a[i] -> sqrt(a[i]),最多执行30次,当a[i]==1后,可以不修改,直接跳过
跳到之后第一个大于1的位置上去,这个位置可以用并查集维护
由于每个点最被修改30次,修改的总复杂度为O(300*N)
注意分析题目中修改操作的性质
注意两个小优化:1. fa[n+1]=n+1
2. if(a[i]>1) fa[i]=i;else fa[i]=i+1;
不知道为什么,这两个去掉哪一个都会TLE很久
【代码】
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
typedef long long LL;
LL a[100005],c[100005];
int fa[100005];
int n;
int father(int x)//father(i):从i起第一个大于1的数的位置
{
if(fa[x]!=x) fa[x]=father(fa[x]);
return fa[x];
}
void xg(int p,int i)
{
for(;i<=n;i+=i&(-i))
c[i]+=p;
}
LL cx(int i)
{
LL sum=0;
for(;i>0;i-=i&(-i))
sum+=c[i];
return sum;
}
int main()
{
int i,m,x,l,r;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
xg(a[i],i);
if(a[i]>1) fa[i]=i;
else fa[i]=i+1;
}
fa[n+1]=n+1;//注意
scanf("%d",&m);
for(;m>0;m--)
{
scanf("%d%d%d",&x,&l,&r);
if(x==1) printf("%lld\n",cx(r)-cx(l-1));//查询
else//修改
{
for(i=father(l);i<=r;i=father(i+1))
{
xg((LL)sqrt((double)a[i])-a[i],i);
a[i]=(LL)sqrt((double)a[i]);
if(a[i]==1) fa[i]=father(i+1);
}
}
}
return 0;
}