题目大意:
维护一个序列,支持区间开方(下取整)和求和操作。n<=100000,ai<=1e12.
解题思路:
一个数最多卡5、6次方就变为了1.
所以如果当前全为1,就不修改,否则暴力修改到底。
查询同普通线段树。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=100005;
int n,m;
ll a[N],sum[N<<2];
void build(int k,int l,int r)
{
if(l==r){sum[k]=a[l];return;}
int mid=l+r>>1;
build(k<<1,l,mid),build(k<<1|1,mid+1,r);
sum[k]=sum[k<<1]+sum[k<<1|1];
}
void modify(int k,int l,int r,int x,int y)
{
if(sum[k]==r-l+1)return;
if(l==r){sum[k]=sqrt(sum[k]);return;}
int mid=l+r>>1;
if(y<=mid)modify(k<<1,l,mid,x,y);
else if(x>mid)modify(k<<1|1,mid+1,r,x,y);
else modify(k<<1,l,mid,x,mid),modify(k<<1|1,mid+1,r,mid+1,y);
sum[k]=sum[k<<1]+sum[k<<1|1];
}
ll query(int k,int l,int r,int x,int y)
{
if(l==x&&r==y)return sum[k];
int mid=l+r>>1;
if(y<=mid)return query(k<<1,l,mid,x,y);
else if(x>mid)return query(k<<1|1,mid+1,r,x,y);
else return query(k<<1,l,mid,x,mid)+query(k<<1|1,mid+1,r,mid+1,y);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
build(1,1,n);
scanf("%d",&m);
while(m--)
{
int op,l,r;scanf("%d%d%d",&op,&l,&r);
if(l>r)swap(l,r);
if(!op)modify(1,1,n,l,r);
else cout<<query(1,1,n,l,r)<<'\n';
}
return 0;
}