hdu1754I Hate It

题目大意:

很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。
这让很多学生很反感。
不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。

题目分析:

对比一下我们前面提过的RMQ问题,这个问题多了一个更新问题。一开始也直接用ST算法加单点更新,但是最后还是无耻的超时了,所以就只能考虑其他方法了,那就是我们接下来需要讲解的线段树了。

(1)什么是线段树?

       线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(logn)。

      线段树的每个节点表示一个区间,子节点则分别表示父节点的左右半区间,例如父亲的区间是[a,b],那么(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b]。

(2)如何构建线段树?

  首先我们来看一颗简单的线段树

假设mid=(父节点.左子树+父节点.右子树)/2,则每个节点的左右子树表示的区间分别为[父节点.左子树,mid],[mid+1,父节点.右子树]

这样我们就可以递归的构建一颗线段树了!

void build(int root,int l,int r){
    tree[root].l=l;
    tree[root].r=r;
    if(l==r){//叶子节点的值就是数组中保存的值
            tree[root].maxScore=Score[l];
            return ;
    }
    int mid=(l+r)/2;
    build(root*2,l,mid);//创建左子树
    build(root*2+1,mid+1,r);//创建右子树
    tree[root].maxScore=Max(tree[root*2].maxScore,tree[root*2+1].maxScore);//父节点的值,等于子节点的最值
}
构建好线段树之后,我们就应该对其进行应用,从上题中我们知道,我们主要的操作有查询和单点更新。

(3)查询:

 查询的时候我们其实也是从更节点开始从上向下开始查,当左区间要大于mid的时候,该区间肯定在当前节点的右子树上,当右区间要小于mid的时候,该区间肯定在当前节点的左子树上。

int get_Max(int root,int l,int r){
    if(tree[root].l==l&&tree[root].r==r){
        return tree[root].maxScore;
    }//如果该节点表示的区间恰好是要查询的区间,直接返回结果
    int mid=(tree[root].l+tree[root].r)>>1;
    if(r<=mid){//判断区间在那颗子树上
        return get_Max(root*2,l,r);
    }
    if(l>mid)
        return get_Max(root*2+1,l,r);
        return Max(get_Max(root*2,l,mid),get_Max(root*2+1,mid+1,r));//如果该区间不在一个节点上,则取两个节点的最值即可
}
(4)单点更新:

 由于是单点更新,我们就直接把更新节点的所有的父节点都更新了。

void update(int root,int index,int new_Score){

    if(tree[root].l==tree[root].r){//找到叶节点了
        tree[root].maxScore=new_Score;
        return ;
    }
    int mid=(tree[root].l+tree[root].r)>>1;
    if(index<=mid)//判断更新节点在哪颗树上
        update(root*2,index,new_Score);
   else
        update(root*2+1,index,new_Score);
        tree[root].maxScore=Max(tree[root*2].maxScore,tree[root*2+1].maxScore);//回溯的时候将所有的父节点给更新了
}

本题代码:

#include<stdio.h>
#include<math.h>
#define N 200009
struct node{
   int l;
   int r;
   int maxScore;
};
node tree[N*2];
int Score[N];
int Max(int a,int b){
   return a>b?a:b;
}
void build(int root,int l,int r){
    tree[root].l=l;
    tree[root].r=r;
    if(l==r){
            tree[root].maxScore=Score[l];
            return ;
    }
    int mid=(l+r)/2;
    build(root*2,l,mid);
    build(root*2+1,mid+1,r);
    tree[root].maxScore=Max(tree[root*2].maxScore,tree[root*2+1].maxScore);
}
void update(int root,int index,int new_Score){

    if(tree[root].l==tree[root].r){
        tree[root].maxScore=new_Score;
        return ;
    }

    int mid=(tree[root].l+tree[root].r)>>1;
    if(index<=mid)
        update(root*2,index,new_Score);
   else
        update(root*2+1,index,new_Score);
        tree[root].maxScore=Max(tree[root*2].maxScore,tree[root*2+1].maxScore);
}
int get_Max(int root,int l,int r){
    if(tree[root].l==l&&tree[root].r==r){
        return tree[root].maxScore;
    }
    int mid=(tree[root].l+tree[root].r)>>1;
    if(r<=mid){
        return get_Max(root*2,l,r);
    }
    if(l>mid)
        return get_Max(root*2+1,l,r);
        return Max(get_Max(root*2,l,mid),get_Max(root*2+1,mid+1,r));
}
int main(){
    int n,m,a,b,i;
    char C;
    while(scanf("%d%d",&n,&m)!=EOF){
            for(i=1;i<=n;i++)
                scanf("%d",&Score[i]);
            build(1,1,n);
            getchar();

        for(i = 1;i<=m;i++)
        {
            scanf("%c%d%d",&C,&a,&b);
            if(C == 'Q')
            {
                printf("%d\n",get_Max(1,a,b));
            }
            else{
                update(1,a,b);
            }
            getchar();
        }
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值