✅ 春招备战指南 ✅
💡 学习建议:
- 先尝试独立解题(建议用时:90分钟/套)
 - 对照解析查漏补缺
 - 配套练习题库
 
互联网必备刷题宝典🔗
📢 美团技术岗笔试重要信息速览
⏰ 笔试时间安排
- 常规场次:每周六交替进行 
  
- 上午场 10:00~11:30
 - 晚间场 19:00~20:30
 
 - 通知时间:每周四/五通过邮箱发送考试链接
 
🧩 笔试题型分布
| 岗位类型 | 题目构成 | 
|---|---|
| 算法岗 | 选择题 + 5道编程 | 
| 后端开发岗 | 选择题 + 3道编程 | 
| 前端/测试岗 | 选择题 + 2道编程 | 
⚙️ 考试设置要点
- 考试平台:牛客网(ACM模式)
 - 监考要求: 
  
- 必须开启笔记本前置摄像头
 - 禁止使用手机(需小程序锁定)
 - 允许使用本地IDE
 
 - 编程规范: 
  
- 严格遵循输入输出格式
 - 注意时间复杂度控制(通常1s对应1e8次运算)
 
 
📚 笔试经验贴
(所有展示题面均已进行改编处理,保留核心考点)
本题库收录整理自:
- 互联网公开的笔试真题回忆版(经网友投稿)
 - 各大技术社区公开讨论的经典题型
 - 历年校招考生提供的解题思路
 
🔍 题库特点:
- 100%真实笔试场景还原
 - 包含高频考点题型
 - 提供多语言实现参考
 - 持续更新2024届最新真题
 
⚠️ 注意事项:
- 所有题目均来自公开渠道,已进行改编脱敏处理
 - 实际笔试可能出现题型变化,请以官方通知为准
 
🚀 春招备战指南
金三银四求职季即将到来!这里整理了最新美团真题及解析,助你快速掌握笔试套路。建议重点突破以下题型:
- 数组/字符串操作
 - 树形结构应用
 - 贪心/动态规划
 - 区间合并问题
 
(👇 下附最新笔试真题及详细解析 👇)
真题详解(改编版)
题目 1: 点头问题
题目描述
两个人面对面坐着交谈,每当他们觉得对方说的不错时就会点头表示赞同。当两人同时点头时,会导致头部碰撞。小基需要在中间伸手阻止碰撞,问小基一共需要伸手几次。
输入格式
第一行输入一个整数 
    
     
      
       
        n
       
      
      
       n
      
     
    n(
    
     
      
       
        1
       
       
        ≤
       
       
        n
       
       
        ≤
       
       
        500
       
      
      
       1≤n≤500
      
     
    1≤n≤500)代表对话时长。
 接下来两行分别输入长度为 
    
     
      
       
        n
       
      
      
       n
      
     
    n 的由 
    
     
      
       
        0
       
      
      
       0
      
     
    0 和 
    
     
      
       
        1
       
      
      
       1
      
     
    1 组成的字符串,表示两人在每个时刻是否点头。
输出格式
输出一个整数,表示小基需要伸手的次数。
样例
输入:
4
1001
0101
 
输出:
1
 
题解
只需要统计两个字符串相同位置同时为 1 的次数即可。时间复杂度 O ( n ) O(n) O(n)。
代码实现
C++:
#include <iostream>
using namespace std;
int main() {
    int len;
    string str1, str2;
    cin >> len >> str1 >> str2;
    
    int cnt = 0;
    for(int i = 0; i < len; i++) {
        if(str1[i] == '1' && str2[i] == '1') {
            cnt++;
        }
    }
    cout << cnt << endl;
    return 0;
}
 
Java:
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int size = scan.nextInt();
        String seq1 = scan.next();
        String seq2 = scan.next();
        
        int total = 0;
        for(int idx = 0; idx < size; idx++) {
            if(seq1.charAt(idx) == '1' && seq2.charAt(idx) == '1') {
                total++;
            }
        }
        System.out.println(total);
    }
}
 
Python:
def count_collisions():
    n = int(input())
    seq_1 = input()
    seq_2 = input()
    
    total = sum(1 for i in range(n) if seq_1[i] == '1' and seq_2[i] == '1')
    return total
if __name__ == "__main__":
    print(count_collisions())
 
题目 2: 染色问题
题目描述
小柯正在对一个长度为 n n n 的数组进行染色。初始时所有元素均为无色。每次可以选择以下操作之一:
- 选择一个位置染成红色
 - 选择一个区间 [ l , r ] [l,r] [l,r],如果该区间内红色元素数量多于无色元素,则将整个区间染成红色
 
求将整个数组染成红色的最少操作次数。
输入格式
第一行输入整数 
    
     
      
       
        T
       
      
      
       T
      
     
    T(
    
     
      
       
        1
       
       
        ≤
       
       
        T
       
       
        ≤
       
       
        1
       
       
        
         0
        
        
         5
        
       
      
      
       1≤T≤10^5
      
     
    1≤T≤105)表示测试用例数。
 每个测试用例一行,输入一个整数 
    
     
      
       
        n
       
      
      
       n
      
     
    n(
    
     
      
       
        1
       
       
        ≤
       
       
        n
       
       
        ≤
       
       
        1
       
       
        
         0
        
        
         9
        
       
      
      
       1≤n≤10^9
      
     
    1≤n≤109)。
输出格式
每个测试用例输出一行,表示最少操作次数。
样例
输入:
3
3
4
12
 
输出:
3
4
6
 
题解
对于长度小于等于 2 的数组,操作次数等于数组长度。对于更长的数组,前两次操作会染红两个位置,之后每次操作可以染红 x − 1 x-1 x−1 个位置( x x x 为当前红色位置数)。时间复杂度 O ( l o g n ) O(log n) O(logn)。
代码实现
C++:
#include <iostream>
using namespace std;
int main() {
    int test_num;
    cin >> test_num;
    
    while(test_num--) {
        long long arr_len;
        cin >> arr_len;
        
        if(arr_len <= 2) {
            cout << arr_len << endl;
            continue;
        }
        
        long long red = 2, ops = 2;
        while(red < arr_len) {
            red += red - 1;
            ops++;
        }
        cout << ops << endl;
    }
    return 0;
}
 
Java:
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int testCnt = scan.nextInt();
        
        while(testCnt-- > 0) {
            long arrSize = scan.nextLong();
            
            if(arrSize <= 2) {
                System.out.println(arrSize);
                continue;
            }
            
            long redCnt = 2, opCnt = 2;
            while(redCnt < arrSize) {
                redCnt += redCnt - 1;
                opCnt++;
            }
            System.out.println(opCnt);
        }
    }
}
 
Python:
def solve_test():
    tests = int(input())
    for _ in range(tests):
        size = int(input())
        if size <= 2:
            print(size)
            continue
            
        red_num, op_num = 2, 2
        while red_num < size:
            red_num += red_num - 1
            op_num += 1
        print(op_num)
if __name__ == "__main__":
    solve_test()
 
题目 3: 标签分配
题目描述
小兰有 m m m 种不同的标签,每种标签只有一个。对于第 i i i 个物品,贴上 a i a_i ai 号标签后美观值为 b i b_i bi,不贴则为 c i c_i ci。求所有物品的最大美观值之和。
输入格式
第一行输入两个整数 
    
     
      
       
        n
       
       
        ,
       
       
        m
       
      
      
       n,m
      
     
    n,m(
    
     
      
       
        1
       
       
        ≤
       
       
        n
       
       
        ,
       
       
        m
       
       
        ≤
       
       
        1
       
       
        
         0
        
        
         5
        
       
      
      
       1≤n,m≤10^5
      
     
    1≤n,m≤105)。
 第二行输入 
    
     
      
       
        n
       
      
      
       n
      
     
    n 个整数 
    
     
      
       
        
         a
        
        
         1
        
       
       
        ,
       
       
        
         a
        
        
         2
        
       
       
        ,
       
       
        .
       
       
        .
       
       
        .
       
       
        ,
       
       
        
         a
        
        
         n
        
       
      
      
       a_1,a_2,...,a_n
      
     
    a1,a2,...,an(
    
     
      
       
        1
       
       
        ≤
       
       
        
         a
        
        
         i
        
       
       
        ≤
       
       
        m
       
      
      
       1≤a_i≤m
      
     
    1≤ai≤m)。
 第三行输入 
    
     
      
       
        n
       
      
      
       n
      
     
    n 个整数 
    
     
      
       
        
         b
        
        
         1
        
       
       
        ,
       
       
        
         b
        
        
         2
        
       
       
        ,
       
       
        .
       
       
        .
       
       
        .
       
       
        ,
       
       
        
         b
        
        
         n
        
       
      
      
       b_1,b_2,...,b_n
      
     
    b1,b2,...,bn(
    
     
      
       
        −
       
       
        10
       
       
        ≤
       
       
        
         b
        
        
         i
        
       
       
        ≤
       
       
        1
       
       
        
         0
        
        
         6
        
       
      
      
       -10≤b_i≤10^6
      
     
    −10≤bi≤106)。
 第四行输入 
    
     
      
       
        n
       
      
      
       n
      
     
    n 个整数 
    
     
      
       
        
         c
        
        
         1
        
       
       
        ,
       
       
        
         c
        
        
         2
        
       
       
        ,
       
       
        .
       
       
        .
       
       
        .
       
       
        ,
       
       
        
         c
        
        
         n
        
       
      
      
       c_1,c_2,...,c_n
      
     
    c1,c2,...,cn(
    
     
      
       
        −
       
       
        1
       
       
        
         0
        
        
         6
        
       
       
        ≤
       
       
        
         c
        
        
         i
        
       
       
        ≤
       
       
        1
       
       
        
         0
        
        
         6
        
       
      
      
       -10^6≤c_i≤10^6
      
     
    −106≤ci≤106)。
输出格式
输出一个整数,表示最大美观值之和。
样例
输入:
3 3
1 2 1
5 4 3
-1 2 -100
 
输出:
6
 
题解
使用贪心算法,按标签分类后,每类中选择美观度增量最大的物品贴标签。时间复杂度 O ( n log  n ) O(n\log n) O(nlogn)。
代码实现
C++:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int calc_max_beauty(int sz, int tag_cnt, vector<int>& tag_type, 
                   vector<int>& with_tag, vector<int>& no_tag) {
    vector<vector<int>> groups(tag_cnt + 1);
    for(int i = 0; i < sz; i++) {
        groups[tag_type[i]].push_back(i);
    }
    
    int sum = 0;
    for(auto& grp : groups) {
        if(grp.empty()) continue;
        
        sort(grp.begin(), grp.end(), 
             [&](int x, int y) { return no_tag[x] - with_tag[x] < no_tag[y] - with_tag[y]; });
             
        sum += max(with_tag[grp[0]], no_tag[grp[0]]);
        for(int i = 1; i < grp.size(); i++) {
            sum += no_tag[grp[i]];
        }
    }
    return sum;
}
int main() {
    int n, m;
    cin >> n >> m;
    vector<int> a(n), b(n), c(n);
    
    for(int i = 0; i < n; i++) cin >> a[i];
    for(int i = 0; i < n; i++) cin >> b[i];
    for(int i = 0; i < n; i++) cin >> c[i];
    
    cout << calc_max_beauty(n, m, a, b, c) << endl;
    return 0;
}
 
题目 4: 地雷引爆
题目描述
小基来到了一个无限大的二维平面上,平面中有 n n n 个地雷。第 i i i 个地雷的坐标为 ( x i , y i ) (x_i,y_i) (xi,yi),在 t i t_i ti 秒时会爆炸,爆炸冲击会引爆与其曼哈顿距离在 k i k_i ki 以内的所有地雷。求至少需要多长时间才能使至少 m m m 个地雷爆炸。
输入格式
第一行输入整数 
    
     
      
       
        T
       
      
      
       T
      
     
    T(
    
     
      
       
        1
       
       
        ≤
       
       
        T
       
       
        ≤
       
       
        100
       
      
      
       1≤T≤100
      
     
    1≤T≤100)表示测试用例数。
 每个测试用例第一行输入两个整数 
    
     
      
       
        n
       
       
        ,
       
       
        m
       
      
      
       n,m
      
     
    n,m(
    
     
      
       
        1
       
       
        ≤
       
       
        m
       
       
        ≤
       
       
        n
       
       
        ≤
       
       
        2000
       
      
      
       1≤m≤n≤2000
      
     
    1≤m≤n≤2000)。
 接下来 
    
     
      
       
        n
       
      
      
       n
      
     
    n 行,每行输入四个整数 
    
     
      
       
        
         x
        
        
         i
        
       
       
        ,
       
       
        
         y
        
        
         i
        
       
       
        ,
       
       
        
         t
        
        
         i
        
       
       
        ,
       
       
        
         k
        
        
         i
        
       
      
      
       x_i,y_i,t_i,k_i
      
     
    xi,yi,ti,ki(
    
     
      
       
        −
       
       
        1
       
       
        
         0
        
        
         9
        
       
       
        ≤
       
       
        
         x
        
        
         i
        
       
       
        ,
       
       
        
         y
        
        
         i
        
       
       
        ≤
       
       
        1
       
       
        
         0
        
        
         9
        
       
       
        ,
       
       
        0
       
       
        ≤
       
       
        
         t
        
        
         i
        
       
       
        ≤
       
       
        1
       
       
        
         0
        
        
         9
        
       
       
        ,
       
       
        0
       
       
        ≤
       
       
        
         k
        
        
         i
        
       
       
        ≤
       
       
        2
       
       
        ×
       
       
        1
       
       
        
         0
        
        
         9
        
       
      
      
       -10^9≤x_i,y_i≤10^9,0≤t_i≤10^9,0≤k_i≤2×10^9
      
     
    −109≤xi,yi≤109,0≤ti≤109,0≤ki≤2×109)。
 所有 
    
     
      
       
        n
       
      
      
       n
      
     
    n 之和不超过 
    
     
      
       
        3000
       
      
      
       3000
      
     
    3000。
输出格式
每个测试用例输出一行,表示最少等待时间。
样例
输入:
1
3 3
0 0 0 1
1 0 1 1
2 2 3 10
 
输出:
3
 
题解
先按爆炸时间排序,用邻接表存储每个地雷能引爆的其他地雷,然后用 DFS 计算连锁反应。时间复杂度 O ( n 2 ) O(n^2) O(n2)。
代码实现
C++:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class MineSolver {
private:
    vector<bool> vis;
    vector<vector<int>> adj;
    
    int dfs(int u) {
        if(!vis[u]) return 0;
        vis[u] = false;
        int sum = 1;
        for(int v : adj[u]) sum += dfs(v);
        return sum;
    }
public:
    void solve() {
        int n, m;
        cin >> n >> m;
        vector<vector<long long>> mines(n, vector<long long>(4));
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < 4; j++) {
                cin >> mines[i][j];
            }
        }
        
        sort(mines.begin(), mines.end(), 
             [](const auto& a, const auto& b) { return a[2] < b[2]; });
        
        adj.assign(n, vector<int>());
        vis.assign(n, true);
        
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                if(abs(mines[i][0] - mines[j][0]) + 
                   abs(mines[i][1] - mines[j][1]) <= mines[i][3]) {
                    adj[i].push_back(j);
                }
            }
        }
        
        int total = 0;
        for(int i = 0; i < n; i++) {
            total += dfs(i);
            if(total >= m) {
                cout << mines[i][2] << '\n';
                break;
            }
        }
    }
};
int main() {
    int t;
    cin >> t;
    MineSolver solver;
    while(t--) solver.solve();
    return 0;
}
 
Java:
import java.util.*;
public class Main {
    static class MineGame {
        private boolean[] visited;
        private List<Integer>[] graph;
        private int[][] mineData;
        
        private int explode(int pos) {
            if(!visited[pos]) return 0;
            visited[pos] = false;
            int count = 1;
            for(int next : graph[pos]) {
                count += explode(next);
            }
            return count;
        }
        
        public void solve(Scanner in) {
            int size = in.nextInt();
            int target = in.nextInt();
            
            mineData = new int[size][4];
            for(int i = 0; i < size; i++) {
                for(int j = 0; j < 4; j++) {
                    mineData[i][j] = in.nextInt();
                }
            }
            
            Arrays.sort(mineData, (a, b) -> Integer.compare(a[2], b[2]));
            
            graph = new List[size];
            visited = new boolean[size];
            for(int i = 0; i < size; i++) {
                graph[i] = new ArrayList<>();
                visited[i] = true;
            }
            
            for(int i = 0; i < size; i++) {
                for(int j = 0; j < size; j++) {
                    if(Math.abs(mineData[i][0] - mineData[j][0]) + 
                       Math.abs(mineData[i][1] - mineData[j][1]) <= mineData[i][3]) {
                        graph[i].add(j);
                    }
                }
            }
            
            int total = 0;
            for(int i = 0; i < size; i++) {
                total += explode(i);
                if(total >= target) {
                    System.out.println(mineData[i][2]);
                    break;
                }
            }
        }
    }
    
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int tests = in.nextInt();
        MineGame game = new MineGame();
        while(tests-- > 0) game.solve(in);
    }
}
 
Python:
class MineField:
    def __init__(self):
        self.vis = []
        self.adj = []
        
    def dfs(self, u):
        if not self.vis[u]:
            return 0
        self.vis[u] = False
        return 1 + sum(self.dfs(v) for v in self.adj[u])
    
    def solve_case(self):
        n, m = map(int, input().split())
        mines = [list(map(int, input().split())) for _ in range(n)]
        mines.sort(key=lambda x: x[2])
        
        self.adj = [[] for _ in range(n)]
        self.vis = [True] * n
        
        for i in range(n):
            for j in range(n):
                if abs(mines[i][0] - mines[j][0]) + abs(mines[i][1] - mines[j][1]) <= mines[i][3]:
                    self.adj[i].append(j)
        
        total = 0
        for i in range(n):
            total += self.dfs(i)
            if total >= m:
                print(mines[i][2])
                break
def main():
    t = int(input())
    solver = MineField()
    for _ in range(t):
        solver.solve_case()
if __name__ == "__main__":
    main()
 
题目 5: 商家替换
题目描述
字符串中的字母可以看作小柯公司里的商家,有实力的商家能够不断取代小的商家。每过一个单位时间,当前商家会被替代为和其相邻位置的最大商家。商家的大小根据 ASCII 码顺序排序: a < b < . . . < z a<b<...<z a<b<...<z。
小柯需要知道字符串 s s s 变为只含单个商家的最少单位时间。他会提出多个区间 [ l , r ] [l,r] [l,r] 的操作或询问:
- 操作一:将字母串 s s s 的第 i i i 个商家替代为商家 p p p
 - 操作二:询问当前字符串 s s s 的 [ l , r ] [l,r] [l,r] 区间变成单个商家需要的最少单位时间
 
输入格式
第一行输入整数 
    
     
      
       
        T
       
      
      
       T
      
     
    T(
    
     
      
       
        1
       
       
        ≤
       
       
        T
       
       
        ≤
       
       
        100
       
      
      
       1≤T≤100
      
     
    1≤T≤100)表示测试用例数。
 每个测试用例第一行输入两个整数 
    
     
      
       
        n
       
       
        ,
       
       
        q
       
      
      
       n,q
      
     
    n,q(
    
     
      
       
        1
       
       
        ≤
       
       
        n
       
       
        ,
       
       
        q
       
       
        ≤
       
       
        2
       
       
        ×
       
       
        1
       
       
        
         0
        
        
         5
        
       
      
      
       1≤n,q≤2×10^5
      
     
    1≤n,q≤2×105)。
 第二行输入长度为 
    
     
      
       
        n
       
      
      
       n
      
     
    n 的小写字母字符串 
    
     
      
       
        s
       
      
      
       s
      
     
    s。
 接下来 
    
     
      
       
        q
       
      
      
       q
      
     
    q 行,每行先输入操作类型 
    
     
      
       
        o
       
       
        p
       
      
      
       op
      
     
    op(
    
     
      
       
        1
       
       
        ≤
       
       
        o
       
       
        p
       
       
        ≤
       
       
        2
       
      
      
       1≤op≤2
      
     
    1≤op≤2):
- 当 o p = 1 op=1 op=1 时,输入整数 i i i 和字符 p p p( 1 ≤ i ≤ n , a ≤ p ≤ z 1≤i≤n,a≤p≤z 1≤i≤n,a≤p≤z)
 - 当 o p = 2 op=2 op=2 时,输入两个整数 l , r l,r l,r( 1 ≤ l ≤ r ≤ n 1≤l≤r≤n 1≤l≤r≤n)
 
输出格式
对于每个操作二,输出一个整数表示最少单位时间。
样例
输入:
2
7 5
adbfdca
2 5 7
1 4 d
2 1 7
2 1 4
2 4 7
5 3
aaaaa
2 1 4
1 2 f
2 1 4
 
输出:
2
2
1
2
0
2
 
题解
使用线段树维护区间内的最大字符及其位置信息。对于每个查询区间,需要计算:
- 最大字符左边的元素需要的时间
 - 最大字符右边的元素需要的时间
 - 最大字符之间的元素需要的时间(间隔除以2)
取三者的最大值即为答案。时间复杂度 O ( q log  n ) O(q\log n) O(qlogn)。 
代码实现
C++:
#include <bits/stdc++.h>
using namespace std;
class SegTree {
    struct Node {
        int left, right;
        char max_val;
        int max_left, max_right;
        int max_gap;
        
        Node(): left(0), right(0), max_val(0), 
               max_left(0), max_right(0), max_gap(0) {}
    };
    
    vector<Node> tree;
    string str;
    
    Node merge(const Node& a, const Node& b) {
        Node res;
        res.left = a.left;
        res.right = b.right;
        
        if(a.max_val == b.max_val) {
            res.max_val = a.max_val;
            res.max_left = a.max_left;
            res.max_right = b.max_right;
            res.max_gap = max({a.max_gap, b.max_gap, 
                             b.max_left - a.max_right});
        } else if(a.max_val > b.max_val) {
            res = a;
        } else {
            res = b;
        }
        return res;
    }
    
    void build(int node, int start, int end) {
        if(start == end) {
            tree[node].left = tree[node].right = start;
            tree[node].max_val = str[start];
            tree[node].max_left = tree[node].max_right = start;
            return;
        }
        
        int mid = (start + end) / 2;
        build(node*2, start, mid);
        build(node*2+1, mid+1, end);
        tree[node] = merge(tree[node*2], tree[node*2+1]);
    }
    
    void update(int node, int start, int end, int pos, char val) {
        if(start == end) {
            str[pos] = val;
            tree[node].max_val = val;
            return;
        }
        
        int mid = (start + end) / 2;
        if(pos <= mid) update(node*2, start, mid, pos, val);
        else update(node*2+1, mid+1, end, pos, val);
        tree[node] = merge(tree[node*2], tree[node*2+1]);
    }
    
    Node query(int node, int start, int end, int l, int r) {
        if(l <= start && end <= r) return tree[node];
        
        int mid = (start + end) / 2;
        if(r <= mid) return query(node*2, start, mid, l, r);
        if(l > mid) return query(node*2+1, mid+1, end, l, r);
        
        return merge(query(node*2, start, mid, l, r),
                    query(node*2+1, mid+1, end, l, r));
    }
    
public:
    SegTree(const string& s): str(s) {
        tree.resize(4 * s.length());
        build(1, 0, s.length()-1);
    }
    
    void update(int pos, char val) {
        update(1, 0, str.length()-1, pos-1, val);
    }
    
    int query(int l, int r) {
        Node res = query(1, 0, str.length()-1, l-1, r-1);
        return max({l-1 - res.max_left,
                   res.max_right - (r-1),
                   res.max_gap/2});
    }
};
void solve() {
    int n, q;
    cin >> n >> q;
    string s;
    cin >> s;
    
    SegTree tree(s);
    while(q--) {
        int op;
        cin >> op;
        if(op == 1) {
            int pos;
            char val;
            cin >> pos >> val;
            tree.update(pos, val);
        } else {
            int l, r;
            cin >> l >> r;
            cout << tree.query(l, r) << '\n';
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int t;
    cin >> t;
    while(t--) solve();
    return 0;
}
 
Java:
import java.util.*;
public class Main {
    static class SegmentNode {
        int leftPos, rightPos;
        char maxChar;
        int maxLeftPos, maxRightPos;
        int maxDistance;
        
        SegmentNode() {
            leftPos = rightPos = maxLeftPos = maxRightPos = maxDistance = 0;
            maxChar = 0;
        }
    }
    
    static class SegmentTree {
        private SegmentNode[] tree;
        private char[] data;
        
        public SegmentTree(String str) {
            data = str.toCharArray();
            tree = new SegmentNode[4 * data.length];
            for(int i = 0; i < tree.length; i++) {
                tree[i] = new SegmentNode();
            }
            buildTree(1, 0, data.length - 1);
        }
        
        private SegmentNode mergeNodes(SegmentNode left, SegmentNode right) {
            SegmentNode result = new SegmentNode();
            result.leftPos = left.leftPos;
            result.rightPos = right.rightPos;
            
            if(left.maxChar == right.maxChar) {
                result.maxChar = left.maxChar;
                result.maxLeftPos = left.maxLeftPos;
                result.maxRightPos = right.maxRightPos;
                result.maxDistance = Math.max(Math.max(left.maxDistance, right.maxDistance),
                                           right.maxLeftPos - left.maxRightPos);
            } else if(left.maxChar > right.maxChar) {
                result.maxChar = left.maxChar;
                result.maxLeftPos = left.maxLeftPos;
                result.maxRightPos = left.maxRightPos;
                result.maxDistance = left.maxDistance;
            } else {
                result.maxChar = right.maxChar;
                result.maxLeftPos = right.maxLeftPos;
                result.maxRightPos = right.maxRightPos;
                result.maxDistance = right.maxDistance;
            }
            return result;
        }
        
        private void buildTree(int node, int start, int end) {
            if(start == end) {
                tree[node].leftPos = tree[node].rightPos = start;
                tree[node].maxChar = data[start];
                tree[node].maxLeftPos = tree[node].maxRightPos = start;
                return;
            }
            
            int mid = (start + end) / 2;
            buildTree(node * 2, start, mid);
            buildTree(node * 2 + 1, mid + 1, end);
            tree[node] = mergeNodes(tree[node * 2], tree[node * 2 + 1]);
        }
        
        public void update(int pos, char val) {
            updateTree(1, 0, data.length - 1, pos - 1, val);
        }
        
        private void updateTree(int node, int start, int end, int pos, char val) {
            if(start == end) {
                data[pos] = val;
                tree[node].maxChar = val;
                return;
            }
            
            int mid = (start + end) / 2;
            if(pos <= mid) {
                updateTree(node * 2, start, mid, pos, val);
            } else {
                updateTree(node * 2 + 1, mid + 1, end, pos, val);
            }
            tree[node] = mergeNodes(tree[node * 2], tree[node * 2 + 1]);
        }
        
        public int query(int left, int right) {
            SegmentNode result = queryTree(1, 0, data.length - 1, left - 1, right - 1);
            return Math.max(Math.max(left - 1 - result.maxLeftPos,
                                   result.maxRightPos - (right - 1)),
                           result.maxDistance / 2);
        }
        
        private SegmentNode queryTree(int node, int start, int end, int left, int right) {
            if(left <= start && end <= right) {
                return tree[node];
            }
            
            int mid = (start + end) / 2;
            if(right <= mid) {
                return queryTree(node * 2, start, mid, left, right);
            }
            if(left > mid) {
                return queryTree(node * 2 + 1, mid + 1, end, left, right);
            }
            
            return mergeNodes(queryTree(node * 2, start, mid, left, right),
                            queryTree(node * 2 + 1, mid + 1, end, left, right));
        }
    }
    
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int tests = scan.nextInt();
        
        while(tests-- > 0) {
            int size = scan.nextInt();
            int queries = scan.nextInt();
            String str = scan.next();
            
            SegmentTree segTree = new SegmentTree(str);
            
            for(int i = 0; i < queries; i++) {
                int op = scan.nextInt();
                if(op == 1) {
                    int pos = scan.nextInt();
                    char val = scan.next().charAt(0);
                    segTree.update(pos, val);
                } else {
                    int left = scan.nextInt();
                    int right = scan.nextInt();
                    System.out.println(segTree.query(left, right));
                }
            }
        }
    }
}
 
Python:
class SegNode:
    def __init__(self):
        self.left = self.right = 0
        self.max_val = ''
        self.max_left = self.max_right = 0
        self.max_gap = 0
class SegmentTree:
    def __init__(self, s: str):
        self.str = list(s)
        self.tree = [SegNode() for _ in range(4 * len(s))]
        self._build(1, 0, len(s) - 1)
    
    def _merge(self, a: SegNode, b: SegNode) -> SegNode:
        res = SegNode()
        res.left = a.left
        res.right = b.right
        
        if a.max_val == b.max_val:
            res.max_val = a.max_val
            res.max_left = a.max_left
            res.max_right = b.max_right
            res.max_gap = max(a.max_gap, b.max_gap, 
                            b.max_left - a.max_right)
        elif a.max_val > b.max_val:
            res.max_val = a.max_val
            res.max_left = a.max_left
            res.max_right = a.max_right
            res.max_gap = a.max_gap
        else:
            res.max_val = b.max_val
            res.max_left = b.max_left
            res.max_right = b.max_right
            res.max_gap = b.max_gap
        return res
    
    def _build(self, node: int, start: int, end: int):
        if start == end:
            self.tree[node].left = self.tree[node].right = start
            self.tree[node].max_val = self.str[start]
            self.tree[node].max_left = self.tree[node].max_right = start
            return
        
        mid = (start + end) // 2
        self._build(node * 2, start, mid)
        self._build(node * 2 + 1, mid + 1, end)
        self.tree[node] = self._merge(self.tree[node * 2], 
                                    self.tree[node * 2 + 1])
    
    def update(self, pos: int, val: str):
        self._update(1, 0, len(self.str) - 1, pos - 1, val)
    
    def _update(self, node: int, start: int, end: int, pos: int, val: str):
        if start == end:
            self.str[pos] = val
            self.tree[node].max_val = val
            return
        
        mid = (start + end) // 2
        if pos <= mid:
            self._update(node * 2, start, mid, pos, val)
        else:
            self._update(node * 2 + 1, mid + 1, end, pos, val)
        self.tree[node] = self._merge(self.tree[node * 2], 
                                    self.tree[node * 2 + 1])
    
    def query(self, l: int, r: int) -> int:
        res = self._query(1, 0, len(self.str) - 1, l - 1, r - 1)
        return max(l - 1 - res.max_left,
                  res.max_right - (r - 1),
                  res.max_gap // 2)
    
    def _query(self, node: int, start: int, end: int, l: int, r: int) -> SegNode:
        if l <= start and end <= r:
            return self.tree[node]
        
        mid = (start + end) // 2
        if r <= mid:
            return self._query(node * 2, start, mid, l, r)
        if l > mid:
            return self._query(node * 2 + 1, mid + 1, end, l, r)
        
        return self._merge(self._query(node * 2, start, mid, l, r),
                          self._query(node * 2 + 1, mid + 1, end, l, r))
def solve():
    n, q = map(int, input().split())
    s = input()
    tree = SegmentTree(s)
    
    for _ in range(q):
        op, *args = map(str, input().split())
        if op == '1':
            pos, val = int(args[0]), args[1]
            tree.update(pos, val)
        else:
            l, r = map(int, args)
            print(tree.query(l, r))
def main():
    t = int(input())
    for _ in range(t):
        solve()
if __name__ == "__main__":
    main()
                
美团春招笔试题解析与备战指南
        
                  
                  
                  
                  
                            
      
          
                
                
                
                
              
                
                
                
                
                
              
                
                
              
            
                  
					424
					
被折叠的  条评论
		 为什么被折叠?
		 
		 
		
    
  
    
  
            


            