HDU1754I Hate It线段树求区间最值和单点修改

开学新拉的题目,老题重做,思路会稍微比之前清晰,不过这也算是一点点进步了。

很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。 
这让很多学生很反感。 

不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。
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

题意:

Q a-b 成绩最高的学生 每一次询问输出成绩
U a、b 把a学生的成绩改为b分

思路:

求区间最值和单点修改
单点修改不需要懒惰标记,因为每次都是访问到底层(最后一个叶节点)

小细节:

|:有1则1
<<1 :等同于*2
i<<1|1:等同于i*2+1

a[4*N]:数组需要开到四倍空间

  1 #include<stdio.h>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<string.h>
  5 #include<cmath>
  6 #include<queue>
  7 #include<stdlib.h>
  8 typedef long long ll;
  9 using namespace std;
 10 const int N=200020;
 11 
 12 //5 6
 13 //1 2 3 4 5
 14 //Q 1 5    ->5
 15 //U 3 6
 16 //Q 3 4    ->6
 17 //Q 4 5    ->5
 18 //U 2 9
 19 //Q 1 5    ->9
 20 
 21 int a[4*N];//需要开到四倍空间
 22 
 23 
 24 //每个父节点记录的是它下面的两个节点的最大值
 25 void build(int L,int R,int i)
 26 {
 27     if(L==R)
 28     {
 29         scanf("%d",&a[i]);
 30         return;
 31     }
 32     int mid=(L+R)>>1;
 33     build(L,mid,i<<1);
 34     build(mid+1,R,i<<1|1);
 35     a[i]=max(a[i<<1],a[i<<1|1]);//pushup(i)////每次传的时候把根节点也往下去寻找最大值
 36     ////比较其左右两个节点的大小,取最大值
 37     //看题目给的需要求什么
 38 }
 39 
 40 //update(aa,bb,1,n,1)
 41 //把下标为aa的元素修改成bb,更新节点值,更改节点
 42 void update(int aa,int bb,int L,int R,int i)
 43 {
 44     if(L==R)
 45     {
 46         a[i]=bb;
 47         return;
 48     }
 49     int mid=(L+R)>>1;
 50     if(aa<=mid)//不是L<=mid
 51         update(aa,bb,L,mid,i<<1);
 52     else
 53         update(aa,bb,mid+1,R,i<<1|1);
 54     a[i]=max(a[i<<1],a[i<<1|1]);
 55 }
 56 
 57 //query(aa,bb,1,n,1)
 58 int query(int left,int right,int L,int R,int i)
 59 {
 60     if(left<=L&&right>=R)
 61         return a[i];
 62     int mid=(L+R)>>1;
 63     int ans=-1;
 64     if(left<=mid)
 65         ans=max(ans,query(left,right,L,mid,i<<1));
 66     // else
 67     if(right>mid)
 68         ans=max(ans,query(left,right,mid+1,R,i<<1|1));
 69     return ans;
 70 }
 71 
 72 int main()
 73 {
 74     int n,m;
 75     while(~scanf("%d %d",&n,&m))
 76     {
 77         memset(a,0,sizeof(a));
 78         build(1,n,1);//传入最左端点,最右端点,根节点进行建树
 79         //建树的过程中输入每一个节点
 80 //    for(int i=1;i<=n;i++)
 81 //        scanf("%d",&a[i]);
 82         string ss;
 83         for(int i=0; i<m; i++)
 84         {
 85             cin>>ss;
 86             int aa,bb;
 87             if(ss=="Q")
 88             {
 89                 scanf("%d %d",&aa,&bb);
 90                 printf("%d\n",query(aa,bb,1,n,1));
 91             }
 92             else
 93             {
 94                 //把下标为aa的元素修改成bb
 95                 scanf("%d %d",&aa,&bb);
 96                 update(aa,bb,1,n,1);
 97             }
 98         }
 99     }
100     return 0;
101 }
原文地址:https://www.cnblogs.com/OFSHK/p/11462368.html