I Hate It HDU - 1754 线段树之单点值修改和区间最大值查询
很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。
这让很多学生很反感。
不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。
这让很多学生很反感。
不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。
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。
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
Hint
Huge input,the C function scanf() will work better than cin
思路:根据线段树的算法首先是正常建立树,然后修改时时间应该值完全变成另一个值,查询时返回大的不再是和而是最大值。
代码:
1 #include <cstdio> 2 #include <fstream> 3 #include <algorithm> 4 #include <cmath> 5 #include <deque> 6 #include <vector> 7 #include <queue> 8 #include <string> 9 #include <cstring> 10 #include <map> 11 #include <stack> 12 #include <set> 13 #include <sstream> 14 #include <iostream> 15 #define mod 998244353 16 #define eps 1e-6 17 #define ll long long 18 #define INF 0x3f3f3f3f 19 using namespace std; 20 21 22 struct node 23 { 24 //l表示左边,r表示右边,sum表示该线段的值 25 int l,r,sum; 26 };//数据一般是点数的十倍 27 node no[2000000]; 28 29 //存放每个点的值 30 int number[200000]; 31 32 //初始化 33 //k表示当前节点的编号,l表示当前区间的左边界,r表示当前区间的右边界 34 void build(int k,int l,int r) 35 { 36 no[k].l=l; 37 no[k].r=r; 38 //如果递归到最低点 39 if(l==r) 40 { 41 //赋值并记录该点对应的节点编号 42 no[k].sum=number[l]; 43 return ; 44 } 45 //对半分 46 int mid=(l+r)/2; 47 //递归到左线段 48 build(k*2,l,mid); 49 //递归到右线段 50 build(k*2+1,mid+1,r); 51 //用左右线段的值更新该线段的值 52 no[k].sum=max(no[k*2].sum,no[k*2+1].sum); 53 } 54 //改边指定节点标号的值 55 //k表示当前节点的编号,要把节点x的sum值变成y 56 void change(int k,int x,int y) 57 { 58 if(no[k].l==no[k].r) 59 { 60 no[k].sum=y; 61 return ; 62 } 63 int mid =(no[k].l+no[k].r)/2; 64 //递归到左线段 65 if(x<=mid) 66 { 67 change(k*2,x,y); 68 } 69 else//递归到右线段 70 { 71 change(k*2+1,x,y); 72 } 73 //用左右线段的值更新该线段的值 74 no[k].sum=max(no[k*2].sum,no[k*2+1].sum); 75 } 76 //查询指定区间内的所有的和 77 //k表示当前节点的编号,l表示当前区间的左边界,r表示当前区间的右边界 78 int query(int k,int l,int r) 79 { 80 //如果当前区间就是询问区间,完全重合,那么显然可以直接返回 81 if(no[k].l==l&&no[k].r==r) 82 { 83 return no[k].sum; 84 } 85 //取中值 86 int mid = (no[k].l+no[k].r)/2; 87 //如果询问区间包含在左子区间中 88 if(r<=mid) 89 { 90 return query(k*2,l,r); 91 } 92 else if(l>mid)//如果询问区间包含在右子区间中 93 { 94 return query(k*2+1,l,r); 95 } 96 else//如果询问区间跨越两个子区间 97 { 98 return max(query(k*2,l,mid),query(k*2+1,mid+1,r)); 99 } 100 } 101 int main() 102 { 103 int n,m; 104 while(scanf("%d %d",&n,&m)!=EOF) 105 { 106 //每个测试样例前都应该初始化数据 107 memset(no,0,sizeof(no)); 108 memset(number,0,sizeof(number)); 109 110 for(int i=1;i<=n;i++) 111 { 112 scanf("%d",&number[i]); 113 } 114 //初始化树 115 build(1,1,n); 116 string str; 117 int a,b; 118 for(int i=0;i<m;i++) 119 { 120 cin>>str>>a>>b; 121 if(str[0]=='Q') 122 { 123 printf("%d\n",query(1,a,b)); 124 } 125 if(str[0]=='U') 126 { 127 change(1,a,b); 128 } 129 } 130 } 131 132 }