线段树例题

上一期讲了线段树的知识,搞个例题玩一下

题目背景

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

题目描述

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

## 输入格式

第一行,有两个正整数 n 和 m,分别代表学生的数目和操作的数目。学生 ID 编号分别从 1 编到 n。

第二行包含 n 个整数,代表这 n 个学生的初始成绩,其中第 i 个数代表 ID 为 i 的学生的成绩,保证学生的成绩为 1 - 10^9 之间的正整数。

接下来有 m 行。每一行有一个字符 c(只取 `Q` 或 `U`),和两个正整数a,b。

- 当 c 为 `Q` 的时候,表示这是一条询问操作,它询问 ID 从 a 到 b(包括 a,b) 的学生当中,成绩最高的是多少;
  • 当 c 为 `U` 的时候,表示这是一条更新操作,如果当前 a 学生的成绩低于 b,则把 ID 为 a 的学生的成绩更改为 b,否则不改动。

## 输出格式

对于每一次询问操作输出一行一个整数,表示最高成绩。

## 输入输出样例 #1

### 输入 #1

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

### 输出 #1

5

6

5

9

题目大意

给定 n 个学生的初始成绩,接下来执行 m 次操作,操作分为两种:

  1. 查询 Q a b:查询编号 a∼b 区间内的最高分数;
  2. 更新 U a b:若编号为 a 的学生当前成绩小于 b,则将其成绩修改为 b,否则不改

算法选型分析

暴力解法(不可行)

ZKW 线段树基础知识

1. 概念由来

ZKW 线段树得名于其提出者张昆玮(缩写 zkw),它是非递归形式的线段树 ,核心思想为自底向上遍历操作,也是算法竞赛里高频使用的模板。

2. 核心结构

ZKW 线段树会把原数组补全为一棵满二叉树

  • 设定变量 bit:代表大于等于元素总数 n 的最小 2 的整数次幂,也是叶子节点区域的起始分界;
  • 叶子节点:专门用来存储原始的学生成绩,对应原数组的每一个元素;
  • 上层节点:每个节点存储对应区间的合并结果,本题中即区间最大值
  • 节点关系:对于任意节点,左子节点、右子节点可以通过位运算快速定位,父子节点关联规则固定。

3. 适用场景与优缺点

  • 适用场景:最擅长处理 单点修改 + 区间求和、区间最值 类问题;
  • 优点:无递归调用,运行常数小、速度快,代码模板简洁;
  • 缺点:实现带懒标记的区间加减、区间乘等复杂操作难度较高,一般不用于这类题型。

解题思路

结合题目要求与 ZKW 线段树的特性,整体分为四大步骤:

  1. 建树 先计算出分界值 bit,将原始成绩存入线段树的叶子节点;再从底层向上遍历,逐层合并区间最大值,完成整棵线段树的初始化。

  2. 单点更新收到更新指令后,先定位到对应学生所在的叶子节点;按照题目规则判断是否需要修改分数,若需要修改,则从该叶子节点一路向上更新所有父节点的区间最大值,保证整棵树数据始终正确。

  3. 区间查询接到查询指令后,将查询区间的左右端点映射到叶子节点下标;通过双指针从底层向根节点移动,沿途收集所有合法区间的最大值,最终得到整个查询区间的最高分。

  4. 批量处理操作循环处理全部 m 条指令,根据指令类型,分别调用更新、查询逻辑,并按要求输出查询结果。

code

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1 << 19;
int n,m,tree[MAXN],bit;

inline void build(int n){
    for(bit=1;bit<=n;bit<<=1);
    for(int i=bit+1;i<=bit+n;i++){
        cin>>tree[i];
    }
    for(int i=bit-1;i;i--){
        tree[i]=max(tree[i<<1],tree[i<<1|1]);
    }
}

inline void update(int ind,int val){
    int pos=bit+ind;
    tree[pos]=val;
    for(pos>>=1;pos;pos>>=1){
        tree[pos]=max(tree[pos<<1],tree[pos<<1|1]);
    }
}

inline int query(int l,int r){
    int res=INT_MIN;
    l+=bit-1;
    r+=bit+1;
    while(l^r^1){
        if(!(l&1)) res=max(res,tree[l^1]);
        if(r&1) res=max(res,tree[r^1]);
        l>>=1;
        r>>=1;
    }
    return res;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin>>n>>m;
    build(n);
    while(m--){
        char c;
        int a,b;
        cin>>c>>a>>b;
        if(c=='Q'){
            cout<<query(a,b)<<'\n';
        }else if(c=='U'){
            if(tree[bit+a]<b){
                update(a,b);
            }
        }
    }
    return 0;
}
相关推荐
故渊at1 小时前
第二板块:Android 四大组件标准化学理 | 第七篇:Activity 页面载体与任务栈算法
android·算法·生命周期·activity·任务栈
兰令水1 小时前
leecodecode【区间DP+树形DP】【2026.6.10打卡-java版本】
java·算法·leetcode
weixin199701080162 小时前
[特殊字符] 1688开放平台API Sign签名算法详解(Java / Python / PHP 实现)
java·python·算法
未若君雅裁2 小时前
JVM 垃圾回收算法与分代回收机制
java·jvm·算法
智者知已应修善业2 小时前
【51单片机初始化D5-D8亮,每按键按下D1到D4全亮,再按下恢复,如此循环】2024-3-26
c++·经验分享·笔记·算法·51单片机
8Qi83 小时前
LeetCode 4:寻找两个正序数组的中位数 —— 二分查找法
java·算法·leetcode·职场和发展·二分查找
8Qi83 小时前
LeetCode 32:最长有效括号 —— 栈 + 标记法 题解
java·数据结构·算法·leetcode·职场和发展··括号匹配
机器学习之心3 小时前
198种组合算法+优化CNN-LSTM+SHAP分析+新数据预测+多输出!深度学习可解释分析,强烈安利,粉丝必备
深度学习·算法·cnn-lstm·shap分析·198种组合算法