一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情。
题目描述
这是codeforces的线段树专题。
C - Segment Tree, part 1 - First element at least X
In this task, you need to add to the segment tree the operation of finding the minimum index j such that a[j]≥x
Input
The first line contains two integers nn and mm (1≤n,m≤100000), the size of the array and the number of operations. The next line contains nn numbers aiai, the initial state of the array (0≤ai≤10^9). The following lines contain the description of the operations. The description of each operation is as follows:
- 1 i v: change the item with index i to vv (0≤i<n, 0≤v≤10^9).
- 2 x: find the minimum index j such that a[j]≥x. If there is no such element, print −1. Indices start from 0.
Output
For each operation of the second type, print the answer for the query.
Example
input
5 7
1 3 2 4 6
2 2
2 5
1 2 5
2 4
2 8
1 3 7
2 6
output
1
4
2
-1
3
问题解析
这题意思就是说,给你一个数组,有两种操作,第一个是把下标为x的变成y,第二个操作是找到数组中的第一个大于x的元素的下标,让你输出这个的下标(比如数组是1 2 3 4 5,那第一个大于2的元素下标就是2,即3)。
建树和单点修改都是基础操作,这题主要点在于怎么利用线段树快速找到第一个大于x的元素。我们可以建树的时候,把每个树的节点f[k]定义为:区间l~r内的最大值。这样我们每次查询的时候,可以比较一下左右子节点的值,先看左节点存储的最大值是否大于x,如果大于,说明第一个大于x的元素应该是出现在左边。如果左节点不大于x,那就去右边找。等找到叶子节点的时候,应该就是我们要找的第一个大于x的节点了。
但是!!题目并没有保证数组里一定有大于x的元素,当数组里没有大于x的元素时,应该输出-1。所以我们到了叶子节点后别急着返回,应该先判断一下叶子节点的值是否大于x,如果大于就返回叶子节点的下标,不大于就返回-1.
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#define endl '\n';
typedef long long ll;
typedef pair<int, int> PII;
const int N = 100050;
int f[4 * N], a[N];
void buildtree(int k,int l,int r)
{
if (l == r)
{
f[k] = a[l];
return;
}
int m = (l + r) / 2;
buildtree(k + k, l, m);
buildtree(k + k + 1, m+1, r);
f[k] = max(f[k + k], f[k + k + 1]);
}
void revise(int k, int l, int r, int x, int y)
{
if (l == r)
{
f[k] = y;
return;
}
int m = (l + r) / 2;
if (x <= m)revise(k + k, l, m, x, y);
else revise(k + k + 1, m + 1, r, x, y);
f[k] = max(f[k + k] , f[k + k + 1]);
}
int quire(int k, int l, int r, int x)
{
if (l == r)
{
if (f[k] >= x)return l;
else return -1;
}
int m = (l + r) / 2;
if (f[k + k] >= x)return quire(k + k, l, m, x);
else return quire(k + k + 1, m + 1, r, x);
}
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)cin >> a[i];
buildtree(1, 1, n);
while (m--)
{
int st, x ,y;
cin >> st;
if (st == 1)
{
cin >> x >> y;
revise(1, 1, n, x + 1, y);
}
else
{
cin >> x;
int res = quire(1, 1, n, x);
if (res != -1)res--;
cout << res << endl;
}
}
return 0;
}