题意:
支持区间开方求和。
题解:
每一位数有效操作次数很少,所以并查集维护右边第一个不为1的数,暴力修改就好了。求和用树状数组。
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
inline ll read(){
char ch=getchar();ll i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
return (f==1)?i:-i;
}
inline void W(ll x){
static int buf[50];
if(!x){putchar('0');return;}
if(x<0){putchar('-');x=-x;}
while(x){buf[++buf[0]]=x%10;x/=10;}
while(buf[0])putchar(buf[buf[0]--]+'0');
}
const int Maxn=1e5+50;
int n,r[Maxn];
ll a[Maxn],bit[Maxn];
inline int getr(int x){return (r[x]==x)?x:(r[x]=getr(r[x]));}
inline void merge(int x,int y){
x=getr(x),y=getr(y);
(x==y)?(0):(r[x]=y);
}
inline void ins(int pos,ll x){
for(;pos<=n;pos+=(pos&(-pos)))bit[pos]+=x;
}
inline ll qry(int pos){
ll res=0;
for(;pos;pos-=(pos&(-pos)))res+=bit[pos];
return res;
}
int main(){
n=read();
for(int i=1;i<=n;i++)r[i]=i,a[i]=read(),ins(i,a[i]);
for(int i=read();i>=1;i--){
int op=read(),bg=read(),ed=read();
if(bg>ed)swap(bg,ed);
if(op==1){W(qry(ed)-qry(bg-1));putchar('\n');continue;}
for(int pos=bg;pos<=ed;pos=getr(pos)+1){
ll t=(ll)(sqrt(a[pos]));
if(t-a[pos])ins(pos,t-a[pos]);
a[pos]=t;
if(a[pos]==1&&pos-1)merge(pos-1,pos);
}
}
}