我们发现每个数被开平方的次数不是太多。
然后1开平方还是1。
然后怎么办?
暴力啊!只要找到没有1的地方暴力做就可以了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 100500
using namespace std;
long long ls[maxn<<3],rs[maxn<<3],value[maxn<<3],n,type,x,y,tot=0,root,m;
long long basic[maxn];
void build(long long &now,long long left,long long right)
{
now=++tot;
if (left==right)
{
value[now]=basic[left];
return;
}
long long mid=(left+right)>>1;
build(ls[now],left,mid);
build(rs[now],mid+1,right);
value[now]=value[ls[now]]+value[rs[now]];
}
void modify(long long now,long long left,long long right,long long l,long long r)
{
if ((left==right) && (value[now]!=1))
{
value[now]=sqrt(value[now]);
return;
}
long long mid=(left+right)>>1;
long long flagl=0,flagr=0;
if (value[ls[now]]!=mid-left+1) flagl=1;
if (value[rs[now]]!=right-mid) flagr=1;
if (r<=mid)
{
if (flagl==1)
modify(ls[now],left,mid,l,r);
}
else if (l>=mid+1)
{
if (flagr==1)
modify(rs[now],mid+1,right,l,r);
}
else
{
if (flagl==1) modify(ls[now],left,mid,l,mid);
if (flagr==1) modify(rs[now],mid+1,right,mid+1,r);
}
value[now]=value[ls[now]]+value[rs[now]];
}
long long query(long long now,long long left,long long right,long long l,long long r)
{
if ((left==l) && (right==r))
return value[now];
long long mid=(left+right)>>1;
if (r<=mid) return query(ls[now],left,mid,l,r);
else if (l>=mid+1) return query(rs[now],mid+1,right,l,r);
else return query(ls[now],left,mid,l,mid)+query(rs[now],mid+1,right,mid+1,r);
}
int main()
{
scanf("%lld",&n);
for (long long i=1;i<=n;i++)
scanf("%lld",&basic[i]);
build(root,1,n);
scanf("%lld",&m);
for (long long i=1;i<=m;i++)
{
scanf("%lld%lld%lld",&type,&x,&y);
if (x>y) swap(x,y);
if (type==0) modify(root,1,n,x,y);
else printf("%lld\n",query(root,1,n,x,y));
}
return 0;
}