题意:
\(n\) 个数,和在 \(10^{18}\) 范围内。
也就是 \(\sum a_i \le10^{18}\)
现在有「两种」操作
0 x y
把区间 \([x,y]\) 内的每个数开方,下取整
1 x y
询问区间 \([x,y]\) 的每个数的和
「格式」: 有多组数据,数据以 EOF 结束,对于每组数据,输出数据的序号,每组数据之后输出一个空行。
「注意」: 不保证给出的区间 \([x, y]\) 有 \(x \le y\) ,如果 \(x>y\) 请交换 \(x,y\) 。
开方有一个性质
\[ \lfloor \sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{10^{18}}}}}}} \rfloor=1 \]
这就说明了,在这个数据范围内,一个数最多被“有效”开方 6 次,对 1 开方我们视为“无效”开方,因为 \(\sqrt1 =1\)
那么我们可以线段树维护两个值 \(sum_u\) 区间和以及 \(max_u\) 区间最大值
如果一个区间内最大值为 1 ,那么这个区间内的数无论开方多少次也不会变,所以就可以不用对这个区间进行操作
如果最大值不是 1,那么就对这个区间内那些不为 1 的点暴力开方,因为一个数最多被“有效”
开方 6 次,所以不会超时
// This code Write By chtholly_micromaker(MicroMaker)
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#define reg register
#define int long long
using namespace std;
const int MaxN=200001;
struct Node
{
int val,sum;
};
template <class t> inline void rd(t &s)
{
s=0;
reg char c=getchar();
while(!isdigit(c))
c=getchar();
while(isdigit(c))
s=(s<<3)+(s<<1)+(c^48),c=getchar();
return;
}
int a[MaxN],n;
struct SegTree
{
#define rt (u>>1)
#define lson (u<<1)
#define rson (u<<1|1)
Node tr[MaxN<<2];
inline void clear()
{
memset(tr,0,sizeof tr);
return;
}
inline void pushup(int u)
{
tr[u].val=max(tr[lson].val,tr[rson].val);
tr[u].sum=tr[lson].sum+tr[rson].sum;
return;
}
inline void buildtr(int u,int l,int r)
{
if(l==r)
{
tr[u].sum=tr[u].val=a[l];
return;
}
reg int mid=(l+r)>>1;
buildtr(lson,l,mid);
buildtr(rson,mid+1,r);
pushup(u);
return;
}
/*
inline void change(int u,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)
{
if(tr[u].val<=1)
return;
reg int maxi=0,res=0;
for(int i=l;i<=r;++i)
maxi=max(maxi,a[i]=sqrt(a[i])),res+=a[i];
tr[u].val=maxi;
tr[u].lazy=maxi;
tr[u].sum=res;
// printf("$$$ %d %d %d\n",l,r,res);
return;
}
reg int mid=(l+r)>>1;
if(ql<=mid)
change(lson,l,mid,ql,qr);
if(mid<qr)
change(rson,mid+1,r,ql,qr);
pushup(u);
return;
}*/
inline void change(int u,int l,int r,int ql,int qr)
{
if(l==r)
{
tr[u].sum=sqrt(tr[u].sum);
tr[u].val=tr[u].sum;
return;
}
reg int mid=(l+r)>>1;
if(ql<=mid&&tr[lson].val>1)
change(lson,l,mid,ql,qr);
if(mid<qr&&tr[rson].val>1)
change(rson,mid+1,r,ql,qr);
pushup(u);
return;
}
inline int query(int u,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)
return tr[u].sum;
// pushdown(u,l,r);
reg int mid=(l+r)>>1,res=0;
if(ql<=mid)
res+=query(lson,l,mid,ql,qr);
if(mid<qr)
res+=query(rson,mid+1,r,ql,qr);
return res;
}
}segtr;
inline void work()
{
reg int opt,x,y;
int m;
segtr.clear();
for(int i=1;i<=n;++i)
rd(a[i]);
segtr.buildtr(1,1,n);
rd(m);
for(int i=1;i<=m;++i)
{
rd(opt);rd(x);rd(y);
if(x>y)
swap(x,y);
if(!opt)
segtr.change(1,1,n,x,y);
else
printf("%lld\n",segtr.query(1,1,n,x,y));
}
return;
}
signed main(void)
{
// freopen("test.out","w",stdout);
int cnt=0;
while(~scanf("%lld",&n))
{
printf("Case #%lld:\n",++cnt);
work();
puts("");
}
return 0;
}