开发一个算法,找出其中的嘴强王者。 输入格式: 第一行两个正整数n,m,表示有n个选手,m次操作(1≤n≤10 5 ,1≤m≤5000)。 第二行有n个整数,分别表示第i个选手的初始嘴炮值a i ;选手的编号从1到n。 接下来有m行,每行三个正整数x,l,r; 当x=1时,这是一个询问操作,询问区间[l,r]里面嘴炮值最高的召唤师,即嘴强王者; 当x=0时,这是一个更新操作,表示选手l的嘴炮值更新为r。 题目保证在每个查询区间内,嘴强王者是唯一的。 输出格式: 对于每个询问操作,在一行里面输出里面的嘴强王者的编号及其嘴炮值,用用空格分隔,行末没有多余空格,C语言具体实现
时间: 2023-10-11 22:06:40 浏览: 148
这道题可以使用线段树来解决。
首先,我们需要一个结构体来表示每个节点:
```c++
struct Node {
int l, r; // 区间左右端点
int maxVal; // 区间内最大值
int maxIdx; // 区间内最大值对应的下标
};
```
然后,我们需要实现以下几个函数:
1. `build()`:建立线段树;
2. `update()`:更新某个叶子节点的值;
3. `query()`:查询某一段区间的最大值。
具体实现如下:
```c++
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, m;
struct Node {
int l, r;
int maxVal;
int maxIdx;
} tr[N << 2];
void pushup(int u) {
if (tr[u << 1].maxVal > tr[u << 1 | 1].maxVal) {
tr[u].maxVal = tr[u << 1].maxVal;
tr[u].maxIdx = tr[u << 1].maxIdx;
} else {
tr[u].maxVal = tr[u << 1 | 1].maxVal;
tr[u].maxIdx = tr[u << 1 | 1].maxIdx;
}
}
void build(int u, int l, int r) {
tr[u] = {l, r};
if (l == r) {
int x;
cin >> x;
tr[u] = {l, r, x, l};
return;
}
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
}
void update(int u, int x, int v) {
if (tr[u].l == x && tr[u].r == x) {
tr[u].maxVal = v;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if (x <= mid) update(u << 1, x, v);
else update(u << 1 | 1, x, v);
pushup(u);
}
Node query(int u, int l, int r) {
if (tr[u].l >= l && tr[u].r <= r) return tr[u];
int mid = tr[u].l + tr[u].r >> 1;
if (r <= mid) return query(u << 1, l, r);
else if (l > mid) return query(u << 1 | 1, l, r);
else {
Node res;
Node left = query(u << 1, l, r);
Node right = query(u << 1 | 1, l, r);
if (left.maxVal > right.maxVal) res = left;
else res = right;
return res;
}
}
int main() {
cin >> n >> m;
build(1, 1, n);
while (m -- ) {
int op;
cin >> op;
if (op == 0) {
int x, v;
cin >> x >> v;
update(1, x, v);
} else {
int l, r;
cin >> l >> r;
Node res = query(1, l, r);
cout << res.maxIdx << " " << res.maxVal << endl;
}
}
return 0;
}
```
时间复杂度为 $O(m\log n)$。
阅读全文