线段树。
很容易发现一个节点开个七八次方就变成1了,每个节点更新八次,最多也就n*8*logn的时间复杂度,完全可以接受,因此可以直接省去延迟更新。
题目最大的坑点在于输入的l和r的顺序可能是相反的,这点注意就没问题了。
附代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define delf int m=(l+r)>>1
#define LL long long int
using namespace std;
const int MAX=100010;
LL sum[MAX<<2];
int rank[MAX<<2];
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
rank[rt]=(rank[rt<<1]|rank[rt<<1|1]);
}
void build(int l,int r,int rt)
{
if (l==r)
{
scanf("%I64d",&sum[rt]);
if (sum[rt]>1)
rank[rt]=1;
return ;
}
delf;
build (lson);
build (rson);
pushup(rt);
return ;
}
void update(int L,int R,int l,int r,int rt)
{
if (rank[rt]==0)
return ;
if (l==r)
{
sum[rt]=(__int64)sqrt(1.0*sum[rt]);
if (sum[rt]<=1)
rank[rt]=0;
return ;
}
delf;
if (m>=L)
update(L,R,lson);
if (R>m)
update(L,R,rson);
pushup(rt);
return ;
}
LL query(int L,int R,int l,int r,int rt)
{
if (L<=l&&r<=R)
return sum[rt];
delf;
LL ans=0;
if (m>=L)
ans+=query(L,R,lson);
if (R>m)
ans+=query(L,R,rson);
pushup(rt);
return ans;
}
int main()
{
int n;
int c=1;
while (~scanf("%d",&n))
{
printf("Case #%d:\n",c++);
build(1,n,1);
int m;
scanf("%d",&m);
while (m--)
{
int p,l,r;
scanf("%d%d%d",&p,&l,&r);
if (l>r)
{
int t=l;
l=r;
r=t;
}
if (p==0)
update(l,r,1,n,1);
else
printf("%I64d\n",query(l,r,1,n,1));
}
printf("\n");
}
}