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 }

猜你喜欢

转载自www.cnblogs.com/mzchuan/p/11759109.html