HDU 6315 Naive Operations (2018多校第2场1007) (线段树+树状数组)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=6315

题意:
给定一个序列b[i];
数列a[i]初始全0;
每次操作可以向a中[l,r]区间+1;
每次求这里写图片描述

分析:
首先将线段树中第i位赋值为b[i],代表i位需要加b[i]次才会对答案+1;
每次区间加操作,认为是对区间-1;
用线段树记录区间最小值及最小值出现的位置;
若区间最小值为0,将这个位置重新赋值为b[i],并在树状数组中对答案+1;
统计答案在树状数组中求和。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int tmax=1e5+5;
int n,ql,qr,b[tmax];
ll v,addv[4*tmax],minv[4*tmax],minnum[4*tmax];
ll _min[2],c[2*tmax];
char s[15];
void query(int x,int l,int r,ll addition)
{
    if(ql<=l&&r<=qr)
    {
        if(_min[0]>minv[x]+addition)
        {
            _min[0]=minv[x]+addition;
            _min[1]=minnum[x];
        }
    }
    else {
        int mid=l+(r-l)/2;
        if(mid>=ql) query(x*2,l,mid,addition+addv[x]);
        if(mid<qr) query(x*2+1,mid+1,r,addition+addv[x]);
    }
    return;
}
void maintain(int x,int l,int r)
{
    int lc=x*2,rc=x*2+1;
    minv[x]=0;
    if(r>l)
    {
        if(minv[lc]<=minv[rc])
        {
            minv[x]=minv[lc];
            minnum[x]=minnum[lc];
        }
        else{
            minv[x]=minv[rc];
            minnum[x]=minnum[rc];
        }
    }
    else minnum[x]=l;
    minv[x]+=addv[x];
    return;
}
void update(int x,int l,int r)
{
    if(ql<=l&&r<=qr) addv[x]+=v;
    else{
        int mid=l+(r-l)/2;
        if(mid>=ql) update(x*2,l,mid);
        if(mid<qr) update(x*2+1,mid+1,r);
    }
    maintain(x,l,r);
    return;
}
int lowbit(int x)
{
    return x&-x;
}
ll sum(int x)
{
    ll ret=0;
    while(x>0)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}
void add(int x)
{
    while(x<=n)
    {
        c[x]++;
        x+=lowbit(x);
    }
    return;
}
int main()
{
    int i,q,tl,tr;
    while(scanf("%d%d",&n,&q)==2)
    {
        memset(addv,0,sizeof(addv));
        memset(minv,0,sizeof(minv));
        memset(c,0,sizeof(c));
        memset(minnum,0,sizeof(minnum));
        for(i=1;i<=n;i++)
        {
            scanf("%d",&b[i]);
            ql=qr=i;
            v=b[i];
            update(1,1,n);
        }
        for(i=1;i<=q;i++)
        {
            scanf("%s%d%d",s,&ql,&qr);
            if(s[0]=='q')
                printf("%I64d\n",sum(qr)-sum(ql-1));
            else{
                v=-1;
                update(1,1,n);
                _min[0]=tmax;
                query(1,1,n,0);
                tl=ql;tr=qr;
                while(_min[0]==0)
                {
                    ql=qr=_min[1];
                    v=b[ql];
                    update(1,1,n);
                    add(ql);
                    ql=tl;qr=tr;
                    _min[0]=tmax;
                    query(1,1,n,0);
                }
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值