一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情。
题目描述
B - Segment Tree, part 2 - B. Inverse and K-th one
There is an array of n booleans, initially filled with zeros. You need to write a data structure that processes two types of queries:
change the value of all elements on a segment from l to r−1 to the opposite, find the index of the k-th one.
Input
The first line contains two numbers n and m (1≤n,m≤100000), the size of the array and the number of operations. The following lines contain the description of the operations. The description of each operation is as follows:
1 l r: change the value of all elements on a segment from l to r−1 to the opposite (0≤l<r≤n), 2 k: the index of the k-th one (ones are numbered from 0, it is guaranteed that there are enough ones in the array). Output For each operation of the second type, print the index of the corresponding one (all indices in this problem are from 0).
Example
input
5 7
1 1 3
2 1
1 0 2
2 0
2 1
1 0 5
2 2
outpu
2
0
2
4
问题解析
这题是说,一开始给你一个数组全是0,有两种操作,一个是修改一个区间里的数组状态,1变0,0变1。一个是让你找到第k个1的位置。
建线段树,每个节点存的是当前区间的区间和,我们把lz标记变成bool类型,当lz为true时,我们就把当前节点的值修改并把标记下传。怎么修改?我们修改数值是把0变成1,1变成0,我们节点计算的是区间和,那么变化后的区间和+变化前的区间和应该=区间长度。
然后至于询问,我们每次根据两个子节点的值判断该去左边还是右边:当左边的区间和大于等于k时,说明第k个1应该在左节点;反之我们去右边找,同时把k减去左节点的值。
(这题有点问题,他说第k个1,但是k的范围是0 ~ n-1的,为了方便我们还是改成1~n比较好)
#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<ll, ll>PII;
const int N = 100010;
ll a[N], f[4 * N];
bool b[4 * N];
void revise(ll k, ll l, ll r, ll x, ll y)
{
if (l == x && r == y)
{
f[k] = r - l - f[k] + 1;
b[k] = !b[k];
return;
}
int m = (l + r) / 2;
if (b[k])
{
b[k + k] = !b[k + k];
f[k + k] = (m - l + 1) - f[k + k];
b[k + k + 1] = !b[k + k + 1];
f[k + k + 1] = (r - m) - f[k + k + 1];
b[k] = false;
}
if (y <= m)revise(k + k, l, m, x, y);
else
if (x > m)revise(k + k + 1, m + 1, r, x, y);
else
{
revise(k + k, l, m, x, m);
revise(k + k + 1, m + 1, r, m + 1, y);
}
f[k] = f[k + k] + f[k + k + 1];
}
ll calc(ll k, ll l, ll r, ll x)
{
if (l == r)return l;
int m = (l + r) / 2;
if (b[k])
{
b[k + k] = !b[k + k];
f[k + k] = (m - l + 1) - f[k + k];
b[k + k + 1] = !b[k + k + 1];
f[k + k + 1] = (r - m) - f[k + k + 1];
b[k] = false;
}
ll res = -1;
if (f[k + k] >= x)res = calc(k + k, l, m, x);
else res = calc(k + k + 1, m + 1, r, x - f[k + k]);
f[k] = f[k + k] + f[k + k + 1];
return res;
}
int main()
{
cin.sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
memset(b, false, sizeof b);
int n, t;
cin >> n >> t;
while (t--)
{
int st, x, y;
cin >> st >> x;
if (st == 1)
{
cin >> y;
revise(1, 1, n, x + 1, y);
}
else
{
cout << calc(1, 1, n, x + 1) - 1 << endl;
}
}
return 0;
}