求区间最大值(线段树?) 您所在的位置:网站首页 求对比值 求区间最大值(线段树?)

求区间最大值(线段树?)

2023-06-02 05:43| 来源: 网络整理| 查看: 265

问题描述:

(pta: 嘴强王者)在召唤师峡谷中,优秀的召唤师总是喜欢比较自己的战斗力强弱,而青铜召唤师也不甘示弱,他们比较嘴炮的强弱。由于他们的嘴炮水平总是不断变化,难以通过人工进行比较,因此请你帮他们开发一个算法,找出其中的嘴强王者。

输入格式:

第一行两个正整数n,m,表示有n个选手,m次操作(1≤n≤105,1≤m≤5000)。

第二行有n个整数,分别表示第i个选手的初始嘴炮值ai;选手的编号从1到n。

接下来有m行,每行三个正整数x,l,r;

当x=1时,这是一个询问操作,询问区间[l,r]里面嘴炮值最高的召唤师,即嘴强王者;

当x=0时,这是一个更新操作,表示选手l的嘴炮值更新为r。

题目保证在每个查询区间内,嘴强王者是唯一的。

输出格式:

对于每个询问操作,在一行里面输出里面的嘴强王者的编号及其嘴炮值,用用空格分隔,行末没有多余空格。

输入样例: 5 6 1 2 3 4 5 1 1 5 0 3 6 1 3 4 1 4 5 0 2 9 1 1 5 输出样例:

在这里给出相应的输出。例如:

5 5 3 6 5 5 2 9 题目分析:

首先想到的是暴力查找,每次遍历 [l, r] ,找到最大值,但是明显会超时O(nm)。

怎么能快速得到 [l, r] 中的最大值呢?假如数组 v[l][r] 刚好存了 [l, r] 的最大值,那么就可以直接得到,但是又出现一个问题,空间不够。

再想一想,假如我们知道 [l, j] 和 [j + 1, r] ,是不是也可以快速求得区间 [l, r] 最大值为 max([l, j], [j + 1, r]) 。

但是要怎么切分呢,这时候应该想到二分,以题目数据为例:

1234501{1,1}2{2,2}3{3,3}4{4,4}5{5,5}12{1,2}4{3,4}5{5,6}24{1,4}5{5,8}35{1,8}

v[0][j] 记录存入的值。

v[1][1] = max(v[0][1], v[0][2]) ,v[1][3] = max(v[0][3], v[0][4]),v[1][5] = max(v[0][5], v[0][6])(关于越界问题可以开更大的空间或者加个条件判断)

v[2][1] = max(v[1][1], v[1][3]) ,v[2][5] = max(v[1][5], v[1][7])

v[3][1] = max(v[2][1], v[2][5])

能找到规律了吗?v[i][j] = max(v[i - 1][j], v[i - 1][j + pow(2, i - 1)]) 其中: j = 0)

所以我们来构造这个数组:

void build() { for (int i = 1; i v[i][j] = max(v[i - 1][j], v[i - 1][j + (span / 2)]); } } }

数组构造完了,接下来是考虑怎么找:

假如我们要找[1, 5] 根据数组提供的数据,可以看出来我们只需要比较[1, 4],[5,5], 即:v[2][4],v[0][5]。

关于怎么得到 v[2][4] 的呢,其中由上面函数build()可看出,v[i][j] 包含了包括j在内的后pow(2, i)个数,所以可以直接通过log2(4 - 1 + 1) 来得到 i。

// 传入的区间[l, r] 和 当前区间[ll, rr]; int find(int l, int r, int ll, int rr) { if (rr r) return 0; // 若当前区间不在查找范围内,则直接返回0 int idx = log2(rr - ll + 1); if (ll >= l && rr if (ll == index) { // 需要更新当前的值 v[0][index] = val; return val; } else return v[0][ll]; } // 更新最大值 return v[idx][ll] = max(update(index, val, ll, mid), update(index, val, mid + 1, rr)); } // 调用 update(l, r, 1, pow(2, h)); 完整代码: #include #include using namespace std; int n, m; int v[18][1 int span = pow(2, i); for (int j = 1; j int idx = log2(rr - ll + 1); int mid = (ll + rr) / 2; if (ll > index || rr v[0][index] = val; return val; } else return v[0][ll]; } // 更新最大值 return v[idx][ll] = max(update(index, val, ll, mid), update(index, val, mid + 1, rr)); } int find(int l, int r, int ll, int rr) { if (rr r) return 0; int idx = log2(rr - ll + 1); if (ll >= l && rr cin >> v[0][i]; mp[v[0][i]].insert(i); } build(); for (int i = 0; i int ans = find(l, r, 1, pow(2, h)); int idx = *mp[ans].lower_bound(l); // 二分快速查找当前的下标 cout


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有