注意到两个地方:
1.
开根后仍然是
2.任何非零数不断开根后最终一定会变为
所以我们在线段树当中标记一个当前区间内的数是否都是 或者 就可以了。
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define SG string
#define DB double
#define LL long long
using namespace std;
inline LL Read(){
LL X=0;char CH=getchar();bool F=0;
while(CH>'9'||CH<'0'){if(CH=='-')F=1;CH=getchar();}
while(CH>='0'&&CH<='9'){X=(X<<1)+(X<<3)+CH-'0';CH=getchar();}
return F?-X:X;
}
inline void Write(LL X){
if(X<0)X=-X,putchar('-');
if(X>9)Write(X/10);
putchar(X%10+48);
}
const LL Max=1e5+5;
struct Node{
LL X,Y,Sum,Lazy;
}Tree[Max<<3];
LL N,M,A[Max];
void MakeTree(LL P,LL X,LL Y){
Tree[P].X=X,Tree[P].Y=Y;
if(X==Y){
Tree[P].Sum=A[X];
if(Tree[P].Sum==1||Tree[P].Sum==0){
Tree[P].Lazy=1;
}
return ;
}
MakeTree(P<<1,X,X+Y>>1);
MakeTree(P<<1|1,(X+Y>>1)+1,Y);
Tree[P].Sum=Tree[P<<1].Sum+Tree[P<<1|1].Sum;
Tree[P].Lazy=Tree[P<<1].Lazy&Tree[P<<1|1].Lazy;
}
void Update(LL P,LL X,LL Y){
if(Tree[P].Lazy==1){
return;
}
if(Tree[P].X==Tree[P].Y){
Tree[P].Sum=sqrt(Tree[P].Sum);
if(Tree[P].Sum==1||Tree[P].Sum==0){
Tree[P].Lazy=1;
}
return;
}
if(Y<=Tree[P<<1].Y){
Update(P<<1,X,Y);
} else if (Tree[P<<1|1].X<=X){
Update(P<<1|1,X,Y);
} else {
Update(P<<1,X,Tree[P<<1].Y);
Update(P<<1|1,Tree[P<<1|1].X,Y);
}
Tree[P].Sum=Tree[P<<1].Sum+Tree[P<<1|1].Sum;
Tree[P].Lazy=Tree[P<<1].Lazy&Tree[P<<1|1].Lazy;
}
LL GetSum(LL P,LL X,LL Y){
if(Tree[P].X==X&&Tree[P].Y==Y){
return Tree[P].Sum;
}
if(Y<=Tree[P<<1].Y){
return GetSum(P<<1,X,Y);
} else if (Tree[P<<1|1].X<=X){
return GetSum(P<<1|1,X,Y);
} else {
return GetSum(P<<1,X,Tree[P<<1].Y)+GetSum(P<<1|1,Tree[P<<1|1].X,Y);
}
}
int main(){
LL I,J,K;
N=Read();
for(I=1;I<=N;I++){
A[I]=Read();
}
MakeTree(1,1,N);
M=Read();
for(I=1;I<=M;I++){
K=Read();LL X=Read(),Y=Read();
if(K==1){
Write(GetSum(1,X,Y)),putchar('\n');
} else {
Update(1,X,Y);
}
}
return 0;
}