hdu-1754 I Hate It线段树(求区间最大值)
Posted 00isok
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu-1754 I Hate It线段树(求区间最大值)相关的知识,希望对你有一定的参考价值。
题目链接:https://vjudge.net/contest/182746#problem/A
I Hate It
Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 96252 Accepted Submission(s): 36407
Problem Description
很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。
这让很多学生很反感。
不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。
这让很多学生很反感。
不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。
Input
本题目包含多组测试,请处理到文件结束。
在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目。
学生ID编号分别从1编到N。
第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。
接下来有M行。每一行有一个字符 C (只取‘Q‘或‘U‘) ,和两个正整数A,B。
当C为‘Q‘的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
当C为‘U‘的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。
在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目。
学生ID编号分别从1编到N。
第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。
接下来有M行。每一行有一个字符 C (只取‘Q‘或‘U‘) ,和两个正整数A,B。
当C为‘Q‘的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
当C为‘U‘的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。
Output
对于每一次询问操作,在一行里面输出最高成绩。
Sample Input
5 6
1 2 3 4 5
Q 1 5
U 3 6
Q 3 4
Q 4 5
U 2 9
Q 1 5
Sample Output
5
6
5
9
解题分析:
以下附代码,以及初学者一些浅薄的理解
#include <iostream> #include <cstdio> using namespace std; const int MAXN = 2000000; int n, m, a[MAXN + 5]; struct tree { int l, r; //每个节点代表一个区间 int v; //v表示这个区间内的最大值 }trees[MAXN * 2]; //用数组来实现线段树,2*i代表第i个节点的左儿子,2*i+1代表第i个节点的右儿子 int max(int a, int b){ return a > b ? a : b;} void buildtree(int rs, int l, int r) //先从根节点将该线段树建好 { trees[rs].l = l; trees[rs].r = r; if (r == l) { trees[rs].v = a[l]; //当构建到叶子的时候,该叶子的值为每一个元素对应的值 return; } int mid = (l + r) / 2; //将该区间均分成两部分 buildtree(rs * 2, l, mid); buildtree(rs * 2 + 1, mid + 1, r); trees[rs].v = max(trees[rs * 2].v, trees[rs * 2 + 1].v); //利用递归,一层一层自下而上给每一个节点赋值 } void update(int rs, int k, int l) { if (trees[rs].l == k && trees[rs].r == k) //如果找到序号为k的叶子,则将该叶子的值更新为l { trees[rs].v = l; return; } int mid = (trees[rs].l + trees[rs].r) / 2; //选择包含序号为k的叶子的路径进行更新,减少不必要的操作 if (k <= mid)update(rs * 2, k, l); if (k>mid)update(rs * 2 + 1, k, l); trees[rs].v = max(trees[rs * 2].v, trees[rs * 2 + 1].v); //利用递归,自下而上的进行更新 } int querry(int rs, int l, int r) { if (trees[rs].l == l && trees[rs].r == r) //如果已经找到需要查询的区间,那么直接返回符合该区间的节点对应的值 return trees[rs].v; int mid = (trees[rs].l + trees[rs].r) / 2; if (r <= mid)return querry(rs * 2, l, r); //如果需要查询的区间完全包含在该节点的左儿子内,则顺着该节点的左儿子继续查找 if (l>mid)return querry(rs * 2 + 1, l, r); if (l <= mid && r>mid) return max(querry(rs * 2, l, mid), querry(rs * 2 + 1, mid + 1, r)); //如果需要查询的区间一部分在左儿子的区间内,另一部分在右儿子的区间内,则该区间的最大值就在[l,mid]或者[mid+1,r]中取得,比较一下两个区间的最大值即可 return 0; //如果不符合条件,则返回0 } int main() { int i, ac, bc; char c; while (scanf("%d %d", &n, &m) != EOF) { for (i = 1; i <= n; i++) scanf("%d", &a[i]); buildtree(1, 1, n); //从根节点将线段树建好 for (i = 1; i <= m; i++) { getchar(); scanf("%c%d%d", &c, &ac, &bc); if (c == ‘Q‘) printf("%d ", querry(1, ac, bc)); //ac,bc分别为将要查询的区间边界 else update(1, ac, bc); //ac表示学生的序号,bc表示该学生更改后的成绩 } } return 0; }
2018-07-19
以上是关于hdu-1754 I Hate It线段树(求区间最大值)的主要内容,如果未能解决你的问题,请参考以下文章
HDU - 1754 I Hate It (线段树单点修改,求区间最大值)
HDU 1754 I Hate It(线段树单点更新区间查询最值)
HDU 1754 I Hate It 线段树单点修改 区间查询
HDU 1754 I Hate It 线段树 单点更新 区间最大值