hdu 4027 Can you answer these queries?

题意:给你N个数,有M个操作,操作有两类,(1)"0 l r",表示将区间[l,r]里的每个数都开根号。(2)"1 l r",表示查询区间[l,r]里所有数的和。

虽然题目给出的数的范围达到了2^63次方,但是,最多开根号7次就会变成1。所以在每次更新的时候,判断,如果这个区间里的所有数被开根号的次数大于7,就不用再往下更新了,其次,因为每个数最多只会有7次开根号,所以在更新的时,可以一直更新到叶子结点。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
#define MID(a,b) (a+((b-a)>>1))
const int N=100005;
typedef long long LL;

struct node
{
    int lft,rht;
    LL cnt,sum;
    int mid(){return MID(lft,rht);}
    int len(){return rht-lft+1;}
};

int n,m;
LL y[N];

struct Segtree
{
    node tree[N*4];
    void up(int ind)
    {
        tree[ind].sum=tree[LL(ind)].sum+tree[RR(ind)].sum;
        if(tree[LL(ind)].cnt>=7&&tree[RR(ind)].cnt>=7)
            tree[ind].cnt=7;
    }
    void build(int lft,int rht,int ind)
    {
        tree[ind].lft=lft;    tree[ind].rht=rht;
        tree[ind].cnt=0;    tree[ind].sum=0;
        if(lft==rht) tree[ind].sum=y[lft];
        else 
        {
            int mid=tree[ind].mid();
            build(lft,mid,LL(ind));
            build(mid+1,rht,RR(ind));
            tree[ind].sum=tree[LL(ind)].sum+tree[RR(ind)].sum;
        }
    }
    void updata(int st,int ed,int ind)
    {
        if(tree[ind].cnt>=7) 
        {
            tree[ind].sum=tree[ind].len();
            return;
        }


        int lft=tree[ind].lft,rht=tree[ind].rht;
        if(st<=lft&&rht<=ed)
        {
            tree[ind].cnt+=1;
            if(lft==rht) 
                tree[ind].sum=(int)sqrt(tree[ind].sum*1.0);
            else
            {
                updata(st,ed,LL(ind));
                updata(st,ed,RR(ind));
                up(ind);
            }
        }
        
        else 
        {
            int mid=tree[ind].mid();
            if(st<=mid) updata(st,ed,LL(ind));
            if(ed> mid) updata(st,ed,RR(ind));
            up(ind);
        }
    }
    LL query(int st,int ed,int ind)
    {
        int lft=tree[ind].lft,rht=tree[ind].rht;
        if(st<=lft&&rht<=ed) return tree[ind].sum;
        else 
        {
            int mid=tree[ind].mid();
            LL sum1=0,sum2=0;
            if(st<=mid) sum1=query(st,ed,LL(ind));
            if(ed> mid) sum2=query(st,ed,RR(ind));
            return sum1+sum2;
        }    
    }
}seg;
int main()
{
    int t_cnt=0;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++) scanf("%I64d\n",&y[i]);
        scanf("%d",&m);


        seg.build(1,n,1);
        


        printf("Case #%d:\n",++t_cnt);
        for(int i=0;i<m;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            if(b>c) swap(b,c);
            if(a==0) seg.updata(b,c,1);
            else printf("%I64d\n",seg.query(b,c,1));
        }
        puts("");
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值