N N N的数组,初始为 1 1 1
支持三种操作
- 将下标为 x x x 的值变为 0 0 0
- 求与下标 x x x 相连的连续的 1 1 1 的长度
- 恢复上一次改为 0 0 0 的操作
分析
线段树维护值01序列
这道题和【Hotel】有点相关
此题要维护x左边相连最远多少 + 右边最远多少
那么我们就维护左端点和右端点最远的距离!
设 l l l 为区间左端点,能预见的最远到右边连续第一个 0 0 0的位置
设 r r r为区间右端点,能预见的最远到左边连续第一个 0 0 0的位置(连续最后一个 1 1 1不就是前一个嘛)
假设区间长度为1,初始化 l = N + 1 l=N+1 l=N+1, r = 0 r=0 r=0,这里就能知道,与之相连的连续 1 1 1的长度为 l − r − 1 l-r-1 l−r−1
注意:(不在区间,就认为都是1,反正看不见,我往上的父节点能够看见,让父亲节点来更新)
假设区间长度为2,那么从左边知道 t r [ l s ] . l , t r [ l s ] . r tr[ls].l,tr[ls].r tr[ls].l,tr[ls].r 右边知道 t r [ r s ] . l , t r [ r s ] . r tr[rs].l, tr[rs].r tr[rs].l,tr[rs].r
此时区间能够预见左边到多远,右边到多远,此时更新能预见的 l l l 和 r r r 值
-
l = min ( t r [ l s ] . l , t r [ r s ] . l ) l = \min(tr[ls].l, tr[rs].l) l=min(tr[ls].l,tr[rs].l)
-
r = m a x ( t r [ l s ] . r , t r [ r s ] . r ) r = max(tr[ls].r,tr[rs].r) r=max(tr[ls].r,tr[rs].r)
这样就能保证从区间 1 1 1推到区间 2 2 2了,由此能够推向区间 4 4 4,信息往上走正确性显然
现在拥有这些信息如何确定某个点连续的大小呢?
对于某个点 x x x来说,我们要知道它连续的点,就要知道 x x x 左边第一个 0 0 0的位置,右边第一个 0 0 0的位置
那么我们可以直接查 x x x的 l l l和 r r r不就得了?
但是, x x x是不能预见左边和右边情况的,它是默认它管理的区间以外都是1
那么谁能够准确预见 x x x的左边情况,和右边情况呢?答案是管理区间 [ 1 , x ] [1, x] [1,x] 和 [ x , N ] [x, N] [x,N] 的节点
[ 1 , x ] [1, x] [1,x] 能够准确知道 r r r 的情况, [ x , N ] [x,N] [x,N]能够知道 l l l 的情况,查询这个得到答案为 l − r − 1 l-r-1 l−r−1
如果 l = = r l==r l==r 的话,说明什么? x x x 就是0,所以答案是 0 0 0
如果要恢复的话,用个栈存一下操作,恢复栈顶操作就行了
不知道有没有说清楚,以下是代码,看代码理解会更轻松
代码
//446928H
/*
@Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define int long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 1e6+5;
const ll MOD = 1e9+7;
int N, M, K;
struct Tr {
int l, r;
Tr operator + (const Tr& B) const {
Tr res;
res.l = min(l, B.l);
res.r = max(r, B.r);
return res;
}
}tr[MAX_N<<2];
void push_up(int rt) {
int lc = rt << 1;
int rc = lc|1;
tr[rt].l = min(tr[lc].l, tr[rc].l);
tr[rt].r = max(tr[lc].r, tr[rc].r);
}
void build(int rt, int l, int r) {
if (l == r) {
tr[rt].l = N+1;
tr[rt].r = 0;
return;
}
int mid = l + ((r-l)>>1);
build(rt<<1, l, mid);
build(rt<<1|1, mid+1, r);
push_up(rt);
}
void update(int rt, int l, int r, int x, int k) {
if (l == r) {
if (!k) {
tr[rt].r = tr[rt].l = x;
} else {
tr[rt].l = N+1;
tr[rt].r = 0;
}
return;
}
int mid = l + ((r-l)>>1);
if (x <= mid) update(rt<<1, l, mid, x, k);
if (x > mid) update(rt<<1|1, mid+1, r, x, k);
push_up(rt);
}
Tr query(int rt, int l, int r, int x, int y) {
if (x <= l && r <= y) {
return tr[rt];
}
int mid = l + ((r-l)>>1);
if (y <= mid) return query(rt<<1, l, mid, x, y);
if (x > mid) return query(rt<<1|1, mid+1, r, x, y);
return query(rt<<1, l, mid, x, y) + query(rt<<1|1, mid+1, r, x, y);
}
int stk[MAX_N];
int tt = 0;
void solve(){
tt = 0;
char opt[5];
int x;
build(1, 1, N);
for (int i = 1; i <= M; ++i) {
sc("%s", opt);
sc("%lld", &x);
if (*opt == 'D') {
stk[++tt] = x;
update(1, 1, N, x, 0);
} else if (*opt == 'Q') {
int r = query(1, 1, N, 1, x).r;
int l = query(1, 1, N, x, N).l;
if (l == r) {
puts("0");continue;
}
pr("%lld\n", l - r - 1);
} else {
if (tt) update(1, 1, N, stk[tt--], 1);
}
}
}
signed main()
{
#ifndef ONLINE_JUDGE
//FILE_IN
FILE_OUT
#endif
int T = 1;//cin >> T;
while (~sc("%lld%lld", &N, &M)) solve();
return AC;
}