本文集合转载自本人博客leen.zw,部分内容参考bilibiliUP主@Nemaleswang
HDU-1754
KEY:单点更新并询问区间最大值
#include<bits/stdc++.h>
#define MAXN 200010
using namespace std;
const int MAXNODE = 1<<19;
struct node{
int v;
int left,right;
}node[MAXNODE];
int f[MAXN];//保存每单个节点的对应下标
void BuildTree(int i,int left,int right){//区间[left,right]建立以i为祖先线段树,i为数组下标即为结点序号
node[i].left = left;//写入第i个节点中的左区间
node[i].right = right;//写入第i个节点中的右区间
node[i].v = 0;//每个区间初始化为0
if(left == right){//区间长度为0时,结束递归
f[left] = i;//记录两边相同(即点)对应的序号,为了更新时从下到顶
return;
}
/*将区间一分为二*/
BuildTree(i<<1,left,(left+right)/2.0);//往左孩子方向继续建立线段树
BuildTree((i<<1)+1,(left+right)/2.0+1,right);//往右
}
void UpdateTree(int ri){//从下往上更新
if(ri == 1)return;//向上找到了祖先(整个线段树的祖先,对应下标为1)
int fi = ri/2.0;//fi为ri的父节点
int a = node[fi<<1].v;//fi的左儿子
int b = node[(fi<<1)+1].v;//fi的右儿子
node[fi].v = max(a,b);//更新fi区间的最大值(将左右儿子的最大值进行比较处理即为fi区间最大值)
UpdateTree(ri/2);//继续递归向上
}
int Max;
void Query(int i,int l,int r){//寻找l到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++;
if(r >= node[i].left) //与上相反
if(l >= node[i].left)Query(i,l,r);
else Query (i,node[i].left,r);
}
int main(){
int n,m,g;
while(scanf("%d%d",&n,&m)!=EOF){
BuildTree(1,1,n);
char ch;
for(int i = 1;i <= n;i++){
scanf("%d",&g);
node[f[i]].v = g;
UpdateTree(f[i]);
}
int a,b;
while(m--){
getchar();
scanf("%c%d%d",&ch,&a,&b);
if(ch == 'Q'){
Max = 0;
Query(1,a,b);
printf("%d\n",Max);
}
else{
node[f[a]].v = b;
UpdateTree(f[a]);
}
}
}
return 0;
}
Tips:位运算 i<<1为二进制下i左移一位,i>>1反之。