範囲最大クエリIII |修復されたセグメントツリー
oj.cupacm.com
制限時間:1秒
メモリ制限:64MB
問題の説明
長さnの配列Aが与えられると、q個のクエリが与えられ、各クエリは、二つの操作のいずれかであってもよい。
1つのLRは、クエリ配列の添字LとRの範囲で最大値を示している。
にAを示しヴァル2つのPOSを配列[POS]の値はヴァルに変更される。
データ・スケール保証:
-1E 6 <= A [i]が≤1e 6
1 <= L <= R <= N
1 <= N、Q <= 100000
入力
入力の最初の行はn、qはシーケンスの長さとクエリの数を表し、
2番目の行はnの数です。
次のq行はそれぞれ操作を示します。
出力
操作1の場合、間隔の最大値を指定します
サンプル入力
5 3
1 3 4 5 2
1 1 4
2 4 8
1 1 4
サンプル出力
5
8
トリミングされたセグメントツリー
ACコード:
#include<cstdio>
#include<iostream>
using namespace std;
int n,m,x[100005]; //原数组
struct Node{
int l,r,w; //区间左右端点和区间最大值
};
Node tree[400005]; //线段树
void build(int num,int l,int r){
//建树
if(l == r){
//相等说明已经到了叶子节点
tree[num].l = l,tree[num].r = r,tree[num].w = x[l];return;
}
int mid = (l + r) >> 1;
int lc = num << 1; //乘2是左子树
int rc = num << 1 | 1; //乘2或1是右子树
build(lc,l,mid); //建左子树
build(rc,mid + 1,r); //建右子树
tree[num].l = l,tree[num].r = r,tree[num].w = max(tree[lc].w,tree[rc].w);return;//保存左右子树的最大子(区间最大)
}
int find(int num,int l,int r){
//查找区间最大
if(tree[num].l == l && tree[num].r == r)//找到目标区间
return tree[num].w;
int mid = (tree[num].l + tree[num].r) >> 1;
int lc = num << 1;
int rc = num << 1 | 1;
if(l > mid) //继续在右子树找
return find(rc,l,r);
else if(r <= mid) //继续在左子树找
return find(lc,l,r);
else return max(find(lc,l,mid),find(rc,mid + 1,r)); //左子树找一段,右子树找一段
}
void pick(int num,int l,int val){
//修改并更新线段树
if(tree[num].l == l && tree[num].r == l){
tree[num].w = val;return;
}
int mid = (tree[num].l + tree[num].r) >> 1;
int lc = num << 1;
int rc = num << 1 | 1;
if(l > mid)
pick(rc,l,val);
else
pick(lc,l,val);
tree[num].w = max(tree[lc].w,tree[rc].w);return;
}
int main(){
scanf("%d %d",&n,&m);
for(int i = 1;i <= n;++i)
scanf("%d",x + i);
build(1,1,n);
while(m--){
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
if(a == 1)
printf("%d\n",find(1,b,c));
else
pick(1,b,c);
}
return 0;
}