hdu 4027 Can you answer these queries?[线段树]

题目

题意:

输入一个 :n  。(1<=n<<100000)

输入n个数    (num<2^63)

输入一个m :代表m个操作    (1<=m<<100000;)

接下来m行,每行三个数a,b,c,如果a==0,执行操作1;如果a==1,执行操作2.   

操作1:对[b,c]区间上的每一个数进行开平方操作

操作2:对[b,c]区间求和,输出。

一直超时,这道题的关键在于: 2^63−1也就最多开8次平方根,,,而且开到1时再开平方根还是1.

所以再开到区间所有数都为1时就不再对这个区间更新,也就是当sum[rt]==r-l+1 时就返回上一层,这样就减小了更新时的操作

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1

using namespace std;
typedef long long LL;
const int maxn = 1e5+10;

LL sum[maxn*4];
int n,m;

int Max(int a,int b)
{
    if(a>b) return a;
    else return b;
}

int Min(int a,int b)
{
    if(a<b) return a;
    else return b;
}
void pushup(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    return ;
}

void build(int l,int r,int rt)
{
    sum[rt]=0;
    if(l==r) {
       scanf("%lld",&sum[rt]);
        return ;
    }
    int mid = (l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void update(int x,int y,int l,int r,int rt)
{
    if(l==r){
        sum[rt]=sqrt(1.0*sum[rt]);
        return;
    }
    if(x<=l&&r<=y&&sum[rt]==r-l+1){
        return;
    }
    int mid = (l+r)>>1;
    if(x<=mid) update(x,y,lson);
    if(mid < y) update(x,y,rson);
    pushup(rt);
}
LL query(int x,int y,int l,int r,int rt)
{
    if(x<=l&&r<=y) return sum[rt];
    int mid = (l+r)>>1;
    LL ans = 0;
    if(x<=mid) ans+=query(x,y,lson);
    if(mid<y) ans+=query(x,y,rson);
    return ans;
}
int main()
{
    int Case = 1;
    int a,b,c,x,y;
    while(~scanf("%d",&n))
    {
        printf("Case #%d:
",Case++);
        build(1,n,1);

        scanf("%d",&m);
        for(int i=0;i<m;i++)
        {
           scanf("%d%d%d",&a,&b,&c);
            x=Min(b,c),y=Max(b,c);
            if(a==0){//update
                update(x,y,1,n,1);
            }else{//query
                LL res = query(x,y,1,n,1);
              printf("%lld
",res);
            }
        }
        printf("
");
    }

    return 0;
}
原文地址:https://www.cnblogs.com/qie-wei/p/10160124.html