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

题面

题意

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

方法

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

修改

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

for(i=1; ii<<=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; i1)
        {
            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
#include
#include
#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; i1)
        {
            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);
            }
        }
    }
}

你可能感兴趣的:(数据结构,树状数组,算法)