刚开始做的时候用线段树做的,然后就跳进坑里了……因为要开方,所以区间的值都得全部变,然后想用lazy标记的,但是发现用不了,单点更新这个用不了,然后就不用了,就T了。然后实在不行了,看了别人的题解,原来是用树状数组+并查集的方法,唉……没想到啊!
因为开方之后多次那个数就会变成1了,所以是1的时候开方下去就没用了。树状数组更新的时候就把其更新的差更新即可,太机智了这题……
昨天做了,然后出错找了好久都找不出来,原来是把s[i]写成c[i]了,然后答案一直错,晕……
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#define PI acos(-1.0)
#define mem(a,b) memset(a,b,sizeof(a))
#define sca(a) scanf("%d",&a)
#define sc(a,b) scanf("%d%d",&a,&b)
#define pri(a) printf("%d\n",a)
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define MM 2000004
#define MN 1008
#define INF 2000000000
#define eps 1e-8
using namespace std;
typedef long long ll;
typedef unsigned long long ULL;
ll c[MM],s[MM];
int f[MM],n;
void update(int x,ll num)
{
for(int i=x;i<=n;i+=i&(-i))
c[i]+=num;
}
ll sum(int x)
{
ll ans=0;
for(int i=x;i>=1;i-=i&(-i))
ans+=c[i];
return ans;
}
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
void solve(int a,int b)
{
for(int i=find(a);i<=b;i=find(i+1))
{
ll k=(ll)sqrt(s[i]);
update(i,k-s[i]);
s[i]=k;
if(k==1) f[i]=i+1;
}
}
int main()
{
int q,i,a,b,k;
sca(n);
for(i=0;i<=n+10;i++) f[i]=i;
for(i=1;i<=n;i++) scanf("%lld",&s[i]),update(i,s[i]);
sca(q);
while(q--)
{
scanf("%d%d%d",&k,&a,&b);
if(a>b) swap(a,b);
if(!k) solve(a,b);
else printf("%lld\n",sum(b)-sum(a-1));
}
return 0;
}