[HDU1754]I Hate It(线段树)

题目大意

给出一段数字,代表1~n的学生的成绩,然后输入命令,一个是查找在[a, b]区间的学生成绩最大值,二是修改指定学生的成绩。从题意中可以看出的是操作的数量可以达到5000,所以用scanf可以防止超时(这次可算长记性了)。

思路

又是一道线段树模版题,以前做过一道区间求和问题。这道题是区间求最大值问题,换汤不换药。思路基本在代码注释中体现了。

代码

#include <cstdio>
#include <climits>
#define Max(a, b)  (a > b ? a : b) 

const int maxn = (2e5 + 1) * 4;

struct node {
    int l, r, maxnum;                              /* l是区间的左边界, r是右边界, maxnum是这个区间的最大的数 */
};

node tree[maxn];                                   /* 用来存线段树的结点 */

int ans;

void build(int l, int r, int k) {                  /* 创建一棵线段树 */
    tree[k].l = l;                                    
    tree[k].r = r;                                 
    if (l == r) {                                   
        scanf("%d", &tree[k].maxnum);              
        getchar();                                 /* 吃回车,因为后面要用scanf吃char,不吃的话下面的吃char的scanf就吃回车了 */
        return;
    }
    int m = (l + r) / 2;
    build(l, m, k * 2);                            
    build(m + 1, r, k * 2 + 1);
    tree[k].maxnum = Max(tree[k * 2].maxnum, tree[k * 2 + 1].maxnum);
}

void query(int l, int r, int k) {                   /* 用来查询l到r区间内的最大值,k是结点的编号,根结点的编号为1 */
    /* 结束递归的条件就是找到这一区间,然后与将这一区间的最大值与ans的大小作比较以找到最大的值 */
    if (l == tree[k].l && tree[k].r == r) { 
        if (tree[k].maxnum > ans)  ans = tree[k].maxnum;
        return;
    }
    int m = (tree[k].l + tree[k].r) / 2;             /* 当前结点区间的中间值 */
    if (r <= m) query(l, r, k * 2);                        
    else if (l > m) query(l, r, k * 2 + 1);          /* 前两个表示这个区间完全在mid的一边,直接调用子结点 */
    else {
        query(l, m, 2 * k);                          /* 找到左右区间的值最大值然后合并 */
        query(m + 1, r, 2 * k + 1);
    }
}

void update (int id, int num, int k) {  
    if (tree[k].r == tree[k].l && tree[k].r == id) {
        tree[k].maxnum = num;
        return;
    }
    int m = (tree[k].r + tree[k].l) / 2;
    if (id > m) update(id, num, k * 2 + 1);
    else update(id, num, k * 2);
    tree[k].maxnum = Max(tree[k * 2].maxnum, tree[k * 2 + 1].maxnum);     /* 合并,这一步很重要 */
}  

int main() {
    //freopen("input.txt", "r", stdin);
    int n, m;          
    while(~scanf("%d%d", &n, &m)) { 
        build(1, n, 1);
        char op;
        int a, b;
        while(m--) {
            ans = INT_MIN;
            scanf("%c%d%d", &op, &a, &b);
            getchar();
            if (op == 'Q') {
                query(a, b, 1);
                printf("%d\n", ans);
            }
            else if (op == 'U'){
                update(a, b, 1);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sunmaoxiang/article/details/80767373