HDU - 1754 I Hate It (树状数组维护区间最值)

21 篇文章 0 订阅
11 篇文章 0 订阅

题面

题意

给出一列数,有两种操作:
1.修改一个数
2.询问区间最大值

方法

用树状数组来维护区间最值,复杂度为O(n*(logn)^2).
做法与维护区间和不同,因为修改最值时无法求出新的最值,但是维护的区间相同.
树状数组维护的区间是[u-lowbit(u)+1,u],可以据此来进行这些操作.

修改

若sz[i]之前的值都正确,则可以发现C[i]可以用这段代码维护.

for(i=1; i<lb(u); i<<=1)
{
    sz[u]=max(sz[u],sz[u-i]);
}

因此只要用这种方法更新所有包含它的区间就行了.

inline void chg(int u,int v)
{
    int i;
    num[u]=v;
    sz[u]=v;
    for(; u<=n; u+=lb(u))
    {
        for(i=1; i<lb(u); i<<=1)
        {
            sz[u]=max(sz[u],sz[u-i]);
        }
    }
}

查询

根据它维护的范围,若要查询[u,v],则可以根据v-lowbit(v)的值进行讨论:
1.u>v-lowbit(v),答案与num[v]取最值,v–
2.u<=v-lowbit(v),答案与sz[v]取最值,v-=lowbit(v).
如此循环,直至u

代码

inline int ask(int u,int v)
{
    int res=0;
    for(; u<=v;)
    {
        res=max(res,num[v]);
        v--;
        for(; v-lb(v)>=u; v-=lb(v))
        {
            res=max(res,sz[v]);
        }
    }
    return res;
}

代码(整道题)

#include<iostream>
#include<cstdio>
#include<cstring>
#define C ch=getchar()
#define N 200100
using namespace std;

int n,m,sz[N],num[N];

inline int lb(int u)
{
    return u&(-u);
}

inline void chg(int u,int v)
{
    int i;
    num[u]=v;
    sz[u]=v;
    for(; u<=n; u+=lb(u))
    {
        for(i=1; i<lb(u); i<<=1)
        {
            sz[u]=max(sz[u],sz[u-i]);
        }
    }
}

inline int ask(int u,int v)
{
    int res=0;
    for(; u<=v;)
    {
        res=max(res,num[v]);
        v--;
        for(; v-lb(v)>=u; v-=lb(v))
        {
            res=max(res,sz[v]);
        }
    }
    return res;
}

int main()
{
    int i,j,p,q;
    char ch;
    while(~scanf("%d%d",&n,&m))
    {
        memset(sz,0,sizeof(sz));
        for(i=1; i<=n; i++)
        {
            scanf("%d",&num[i]);
            chg(i,num[i]);
        }
        for(i=1; i<=m; i++)
        {
            for(C; ch!='Q'&&ch!='U'; C);
            scanf("%d%d",&p,&q);
            if(ch=='Q')
            {
                printf("%d\n",ask(p,q));
            }
            else
            {
                chg(p,q);
            }
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值