HDU

题目传送门:HDU - 4027 Can you answer these queries? 

题目大意:

存在n艘敌军战舰,每艘战舰都有能量值,我军存在一种秘密武器,每次能够将在该区间内的所

有战舰的能量值开方,现在指挥官想要知道武器的效果,需要你告诉他该区间内敌军战舰的能

量值之和

分析:

该题对区间进行操作,显然是用线段树。两个操作分别是对区间进行开方和区间求和,对区间中战舰的能量值

进行开方操作,很简单的会想到用lazy数组,但会发现无法像区间加减写出类似的式子。仔细想便可发现数据

最大值为2 63,因此没个数最多能开6-7次方,之后1开方仍然为1.因此如果一个区间中的值全为1,则他就不需

要再进行任何操作即可。若区间不满足条件则进行单点更新,将每个值开方即可。区间求和就是很普通的区间

求和了

//判断区间是否全为1
if(sum[rt]==r-l+1)return;

代码:

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
typedef long long ll;
const int MAX=100009;
int n,m,t,x,y;
ll sum[MAX<<2];
void PushUp(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
 } 
void Build(int l,int r,int rt)
{
    if(l==r)
    {
        scanf("%lld",&sum[rt]);
        return;
    }
    int m=l+r>>1;
    Build(ls);
    Build(rs);
    PushUp(rt);
}
void Update(int L,int R,int l,int r,int rt)
{
    if(sum[rt]==r-l+1)return;        //判断区间是否全为1 
    if(l==r)
    {
        sum[rt]=(ll)(sqrt(sum[rt]));    //直接开方即可
        return;
    }
    int m=(l+r)>>1;
    if(L<=m)Update(L,R,ls);
    if(R>m)Update(L,R,rs);
    PushUp(rt);
}
ll Query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        return sum[rt];
    }
    int m=l+r>>1;
    ll ans=0;
    if(L<=m)ans+=Query(L,R,ls);
    if(R>m)ans+=Query(L,R,rs);
    return ans;
}
int main()
{
    int f=1;
    while(scanf("%d",&n)!=EOF)
    {
        printf("Case #%d:
",f++);
        memset(sum,0,sizeof(sum));
        Build(1,n,1);
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d%d%d",&t,&x,&y);
            if(x>y)swap(x,y);
            if(t==0)
                Update(x,y,1,n,1);
            if(t==1)
                printf("%lld
",Query(x,y,1,n,1));
        }
        printf("
"); 
    }
    return 0;
}
原文地址:https://www.cnblogs.com/LjwCarrot/p/10714314.html