这道题有点意思。
题意如下
一个数组,两种操作
一个是 对区间 l r 开方
另一个 就是 求 l r 之间和
看似是区间修改,但是发现了一个问题,一个数如果被开方太多次最后就会到1,
粗略算下 一个数 不断平方的话
大概 从 2 开始 不断平方 感觉能在10次之内 爆掉 long long 所以区间修改的话并不需要严格意义上的 lazy 标记
我们只需要标记一下是否是 1 ,如果是 1 了开放也没有意义了,所以如果情况够坏,所有数都在十次内变回 1,大概 1e6,询问 还是logn 总时间的话 没好好算。。但是莽了一下过了。。。。
以下是 AC 代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn = 1e6+5;
#define ll long long int
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
ll num[maxn],col[maxn];
void pushup(int rt)
{
num[rt] = num[rt<<1] + num[rt<<1|1];
col[rt] = col[rt<<1] && col[rt<<1|1];
}
void build(int l,int r,int rt)
{
col[rt] = 0;
if(l == r)
{
scanf("%lld",&num[rt]);
return;
}
int m = (l+r)/2;
build(lson);
build(rson);
pushup(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
if(L<=l && R>=r)
return num[rt];
int m = (l+r)/2;
ll res = 0;
if(L <= m)
res += query(L,R,lson);
if(R > m)
res += query(L,R,rson);
return res;
}
void update(int L,int R,int l,int r,int rt)
{
if(l == r)
{
num[rt] = (ll)sqrt(num[rt]);
if(num[rt] == 1)
col[rt] = 1;
return;
}
int m = (l+r)/2;
if(L<=m && !col[rt<<1])
update(L,R,lson);
if(R>m && !col[rt<<1|1])
update(L,R,rson);
pushup(rt);
}
int main()
{
int n,m;
for(int cas=1;~scanf("%d",&n);cas++)
{
build(1,n,1);
scanf("%d",&m);
printf("Case #%d:\n",cas);
while(m--)
{
int op,a,b;
scanf("%d%d%d",&op,&a,&b);
if(a>b)
swap(a,b);
if(op == 0)
{
update(a,b,1,n,1);
}
else
{
printf("%lld\n",query(a,b,1,n,1));
}
}
puts("");
}
return 0;
}