Rikka with Sequence HDU - 5828(线段树)

本文详细解析了HDU-5828 RikkawithSequence题目,介绍了使用线段树实现区间加法、区间开方和区间求和操作的方法。通过具体的代码示例,展示了如何处理懒惰标记和节点更新,以高效解决复杂的数据结构问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Rikka with Sequence

HDU - 5828

As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:

Yuta has an array A with n numbers. Then he makes m operations on it.

There are three type of operations:

1 l r x : For each i in [l,r], change A[i] to A[i]+x
2 l r : For each i in [l,r], change A[i] to ⌊A‾‾√[i]⌋
3 l r : Yuta wants Rikka to sum up A[i] for all i in [l,r]

It is too difficult for Rikka. Can you help her?

 

区间开根号,区间+,区间查询和



    const long long maxn = 1e6+11;
    long long sum[maxn],minv[maxn],maxv[maxn],lazy[maxn],tag[maxn];//lazy,tag均为懒惰标记

    void pushup(long long i)
    {
        sum[i] = sum[i<<1] + sum[i<<1|1];
        maxv[i] = max(maxv[i<<1],maxv[i<<1|1]);
        minv[i] = min(minv[i<<1],minv[i<<1|1]);
    }

    void pushcover(long long i,long long l,long long r,long long v)
    {
        lazy[i] = 0;
        sum[i] = (r-l+1)*v;
        tag[i] = maxv[i] = minv[i] = v;
    }

    void pushnow(long long i,long long l,long long r,long long v)
    {
        sum[i] += (r-l+1)*v;
        lazy[i] += v;
        maxv[i] += v;
        minv[i] += v;
    }

    void pushdown(long long i,long long l,long long r)
    {
        long long mid = (l+r)>>1;
        if(tag[i]!=-1)
        {
            pushcover(i<<1,l,mid,tag[i]);
            pushcover(i<<1|1,mid+1,r,tag[i]);
            tag[i] = -1;
        }
        if(lazy[i])
        {
            pushnow(i<<1,l,mid,lazy[i]);
            pushnow(i<<1|1,mid+1,r,lazy[i]);
            lazy[i] = 0;
        }
    }

    void update1(long long i,long long l,long long r,long long ql,long long qr,long long v)
    {
        //if(ql > r || qr < l)return;
        if(ql <= l && r <= qr)
        {
            pushnow(i,l,r,v);return;
        }
        long long mid = (l+r)>>1;
        pushdown(i,l,r);
        if(ql <= mid)update1(i<<1,l,mid,ql,qr,v);
        if(qr > mid)update1(i<<1|1,mid+1,r,ql,qr,v);
        pushup(i);
    }

    void update2(long long i,long long l,long long r,long long ql,long long qr)
    {
        //if(ql > r || qr < l)return;
        if(ql <= l && qr >= r && maxv[i] - minv[i] <= 1)
        {
            long long x = sqrt(maxv[i]),y = sqrt(minv[i]);
            if(x == y)pushcover(i,l,r,x);//区间一样
            else pushnow(i,l,r,x-maxv[i]);//区间-
            return;
        }
        long long mid = (l+r)>>1;
        pushdown(i,l,r);
        if(ql <= mid)update2(i<<1,l,mid,ql,qr);
        if(qr > mid)update2(i<<1|1,mid+1,r,ql,qr);
        pushup(i);
    }

    long long query(long long i,long long l,long long r,long long ql,long long qr)
    {
        
        if(ql<=l && qr>=r)return sum[i];
        long long mid = (l+r)>>1;
        pushdown(i,l,r);
        long long ans = 0;
        if(ql<=mid) ans += query(i<<1,l,mid,ql,qr);
        if(qr>mid) ans+=query(i<<1|1,mid+1,r,ql,qr);
        return ans;
    }

    void build(long long i,long long l,long long r)
    {
        lazy[i] = 0,tag[i] = -1;
        long long mid = (l+r)>>1;
        if(l==r)
        {
            long long x;
            scanf("%lld",&x);
            maxv[i] = minv[i] = sum[i] = x;
            return;
        }
        build(i<<1,l,mid);
        build(i<<1|1,mid+1,r);
        pushup(i);
    }
    int main() 
    {   
        long long T;cin>>T;
        while(T--)
        {
            long long n,m;scanf("%lld%lld",&n,&m);
            build(1,1,n);
            while(m--)
            {
                long long op,l,r;
                scanf("%lld%lld%lld",&op,&l,&r);
          
                if(op == 1)
                    {long long v;scanf("%lld",&v),update1(1,1,n,l,r,v);}//区间+
                else if(op == 2)
                    update2(1,1,n,l,r);//区间开根号
                else printf("%lld\n",query(1,1,n,l,r)); //区间
            }
        }
        return 0;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值