题意:有两个正整数 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)的学生当中,成绩最高的是多少。
学生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。
对于每一次询问操作,在一行里面输出最高成绩。
这题是一道最基础的线段树模板题,没什么难度,就是单点更新和求区间最大值。
我参照了两个模板,一个用了结构体
代码1:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n,m;
int maxn[200000 << 2];
void build(int rt, int l, int r)
{
if(l == r)
{
scanf("%d",&maxn[rt]);
return;
}
int mid = (l + r) >> 1;
build(rt << 1, l, mid);
build(rt << 1|1, mid + 1, r);
maxn[rt] = max(maxn[rt << 1],maxn[rt << 1|1]);
}
void update(int x, int z, int l, int r, int rt)
{
if(l == r) // 更新到叶子节点
{
maxn[rt] = z;
return;
}
int mid = (l + r) >> 1;
if(x <= mid)
update(x, z, l, mid, rt << 1);
else update(x, z, mid + 1, r, rt << 1|1);
maxn[rt] = max(maxn[rt << 1],maxn[rt << 1|1]);
}
int query(int L, int R, int l, int r, int rt)
{
if(L <=l && r <=R)
{
return(maxn[rt]);
}
int mid = (l + r) >> 1;
int Max = 0;
if(L <= mid) //这里拆分区间
Max = max(Max,query(L, R, l, mid ,rt << 1));
if(R > mid) //区间的左右两部分都要加进去,所以此处没有else语句
Max = max(Max,query(L, R, mid + 1, r, rt << 1|1));
return(Max);
}
int main()
{
while(~scanf("%d %d",&n, &m))
{
build(1,1,n);
for(int j=1;j<=m;j++)
{
getchar();
char c;
int a,b;
scanf("%c %d %d",&c, &a, &b);
if(c == 'Q')
{
printf("%d\n",query(a,b,1,n,1));
}
else if(c == 'U')
{
update(a,b,1,n,1);
}
}
}
return 0;
}
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
struct aa
{
int v;
int left,right;
}node[524288];
int father[200001];//每个点(当区间长度为0时,对应一个点)对应的结构体数组下标
int Max;
int n,m;
void BuildTree(int i, int left, int right)
{
node[i].left = left;
node[i].right = right;
node[i].v = 0;
if(left == right)
{
father[left]=i;
return;
}
BuildTree(i << 1 , left , (left + right)/2);
BuildTree((i << 1)+1 , (left + right)/2 + 1, right);
}
void UpdateTree(int ri)//该点本身在函数外已更新过
{
if(ri == 1)return;
int fi = ri / 2; //父节点,从下往上更新
int a = node[fi << 1].v;
int b = node[(fi << 1) + 1].v;
node[fi].v = max(a,b);
UpdateTree(ri/2);
}
void Query(int i, int l ,int r)
{
if(node[i].left == l && node[i].right == r)
{
Max=max(Max,node[i].v);
return;
}
i= i << 1;
if(l <= node[i].right )
{
if(r <= node[i].right)
Query(i, l, r);
else
Query(i, l ,node[i].right);
}
i +=1; // 右子树
if(r >= node[i].left)
{
if(l >= node[i].left)
Query(i, l, r);
else
Query(i, node[i].left, r);
}
}
int main()
{
while(scanf("%d %d",&n,&m)!=EOF)
{
BuildTree(1, 1, n);
for(int i=1;i<=20;i++)
printf("%d ",node[i].v);
printf("\n");
for(int i=1;i<=n;i++)
{
int a;
scanf("%d",&a);
node[father[i]].v = a;
UpdateTree(father[i]);
for(int i=1;i<=20;i++)
printf("%d ",node[i].v);
printf("\n");
}
for(int i=1;i<=m;i++)
{
int A,B;
char c;
getchar();
scanf("%c %d %d",&c,&A,&B);
//printf("%c\n",c);
if(c == 'Q')
{
Max=-1000000;
Query(1, A, B);
printf("%d\n",Max);
}
else if(c == 'U')
{
node[father[A]].v = B;
UpdateTree(father[A]);
}
}
}
return 0;
}