题意:
给一个数组序列, 数组长度为100000
两种操作: 一种操作是将某一个固定区间所有数开方(向下取整)
另一种操作是询问某个区间的所有数字之和。
思路:
数据范围2^64,最多开6、7次就到1,所以判断当sum[rt]==r-l+1时 return(相当于剪枝),由于更新比较特别,此题不需要lazy数组。最后注意query的数据左不一定小于右,所以要交换一下,还有就是以后不要混用scanf和cin了。。。WA了无数次就是因为这个!!!
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn=100005;
const int mod=1e9+7;
const double eps=1e-8;
const double PI = acos(-1.0);
#define lowbit(x) (x&(-x))
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll qpow(ll a,ll b){ll t=1;while(b){if(b%2){t=(t*a)%mod;b--;}a=(a*a)%mod;b/=2;}return t;}
ll inv(ll a,ll p){return qpow(a,p-2);}
ll a[maxn<<2],sum[maxn<<2];
void pushUp(ll rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(ll l,ll r,ll rt)
{
sum[rt]=0;
if(l==r)
{
sum[rt]=a[l];
return ;
}
ll m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
pushUp(rt);
}
void update(ll L,ll R,ll l,ll r,ll rt)
{
if(L <= l && r <= R &&sum[rt]==r-l+1)
{
return ;
}
if(l==r)
{
sum[rt]=(ll)sqrt((double)sum[rt]);
return ;
}
ll m=(l+r)>>1;
if(L<=m) update(L,R,l,m,rt<<1);
if(R>m) update(L,R,m+1,r,rt<<1|1);
pushUp(rt);
}
ll query(ll L,ll R,ll l,ll r,ll rt)
{
if(L<=l&&r<=R)
{
return sum[rt];
}
ll m=(l+r)>>1;
ll ans=0;
if(L<=m) ans+=query(L,R,l,m,rt<<1);
if(R>m) ans+=query(L,R,m+1,r,rt<<1|1);
return ans;
}
int main()
{
std::ios::sync_with_stdio(false);
int n,cas=0;
while(~scanf("%d",&n))
{
// memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
build(1,n,1);
ll m;
scanf("%lld",&m);
printf("Case #%d:\n",++cas);
while(m--)
{
ll t,b,c;
scanf("%lld%lld%lld",&t,&b,&c);
if(b>c) swap(b,c);
if(!t)
{
update(b,c,1,n,1);
}
else
{
printf("%lld\n",query(b,c,1,n,1));
}
}
puts("");
}
return 0;
}