LINK
题意翻译
「题意」: nnn 个数,和在101810^{18}1018 范围内。
也就是∑ ai ≤ 1018\suma_i\leq~10^{18}∑ ai ≤ 1018
现在有「两种」操作
0 x y把区间[x,y][x,y][x,y] 内的每个数开方,下取整
1 x y询问区间[x,y][x,y][x,y] 的每个数的和
「格式」: 有多组数据,数据以EOF结束,对于每组数据,输出数据的序号,每组数据之后输出一个空行。
「注意」: 不保证给出的区间[x,y][x, y][x,y] 有x<=yx <= yx<=y ,如果x>yx>yx>y 请交换xxx ,yyy 。
感谢@Edgration 提供的翻译
输入输出样例
输入 #1
5
1 2 3 4 5
5
1 2 4
0 2 4
1 2 4
0 4 5
1 1 5
4
10 10 10 10
3
1 1 4
0 2 3
1 1 4
输出 #1
Case #1:
9
4
6
Case #2:
40
26
#include<bits/stdc++.h>
using namespace std;
int n;typedef long long ll;
const int N=100010;
struct node
{
ll a,maxn;
// maxn表示子树的最大值,image 如果最大值是1 那么就不要考虑update 了 好像最大的数字也最大6 次就可以开方成1 大大减少更新时间
void init()
{
a=maxn=0;
}
}t[N<<2];
void up(int rt)
{
t[rt].a=t[rt<<1|1].a+t[rt<<1].a;
t[rt].maxn=max(t[rt<<1|1].maxn,t[rt<<1].maxn);
}
void build(int l,int r,int rt)
{
t[rt].init();
if(l==r)
{
ll a;scanf("%lld",&a);
t[rt]=(node){a,a};return ;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
up(rt);
}
void update(int L,int R,int l,int r,int rt)
{
if(t[rt].maxn<=1) return ;//这种情况取sqrt无意义了
if(l==r)
{
t[rt].a=sqrt(t[rt].a );
t[rt].maxn=t[rt].a;
return ;
}
int mid=(l+r)>>1;
if(mid>=L) update(L,R,l,mid,rt<<1);
if(mid<R) update(L,R,mid+1,r,rt<<1|1);
up(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
if(l>=L&&r<=R)
{
return t[rt].a ;
}
int mid=(l+r)>>1; ll s=0;
if(mid>=L) s+=query(L,R,l,mid,rt<<1);
if(mid<R) s+=query(L,R,mid+1,r,rt<<1|1);
return s;
}
int main()
{
int cas=0;
while(~scanf("%d",&n))
{
build(1,n,1);
int m;
scanf("%d",&m);
printf("Case #%d:\n",++cas);
while(m--)
{
int op,l,r;scanf("%d%d%d",&op,&l,&r);
if(l>r) swap(l,r);
if(op==1)
{
printf("%lld\n",query(l,r,1,n,1));
}else
{
update(l,r,1,n,1);
}
}
}
}