题意
有长度为 n n n 的序列 a a a 和 01 01 01序列 b b b,有 m m m 次操作,每次操作给出 l , r l,r l,r。每个操作为以下三种之一:
- 将 a l a_l al 改成 r r r
- 将 b l , b l + 1 . . . , b r b_l,b_{l+1}...,b_r bl,bl+1...,br 翻转 (即 b i = ( b i + 1 ) m o d 2 b_i=(b_i+1)~mod~2 bi=(bi+1) mod 2)
- 设 [ l , r ] [l,r] [l,r] 中 a a a 形成的单调栈下标序列为 p p p,满足 a p k ≥ a p k − 1 a_{p_k}\ge a_{p_{k-1}} apk≥apk−1。求 b p k ≠ b p k + 1 b_{p_k}\neq b_{p_{k+1}} bpk=bpk+1 的数量。
其中, 1 ≤ n ≤ 2 × 1 0 5 , 0 ≤ a i ≤ 1 0 9 , 0 ≤ b i ≤ 1 1\le n\le 2\times 10^5,0\le a_i\le 10^9,0\le b_i\le 1 1≤n≤2×105,0≤ai≤109,0≤bi≤1。
分析
令
c
a
l
(
l
,
r
,
x
,
p
)
cal(l,r,x,p)
cal(l,r,x,p) 表示单调栈上一个的值为
x
x
x,位置为
p
p
p,经过
l
,
r
l,r
l,r 之后多出来的答案。我们用线段树维护区间最大值
m
x
mx
mx 和区间最大值最靠右的位置
m
p
mp
mp。
如果
m
x
l
s
o
n
<
x
mx_{lson}<x
mxlson<x,那么
c
a
l
(
l
,
r
,
x
,
p
)
=
c
a
l
(
m
+
1
,
r
,
x
,
p
)
cal(l,r,x,p)=cal(m+1,r,x,p)
cal(l,r,x,p)=cal(m+1,r,x,p)。
如果
m
x
l
s
o
n
≥
x
mx_{lson}\ge x
mxlson≥x,那么
c
a
l
(
l
,
r
,
x
,
p
)
=
c
a
l
(
l
,
m
,
x
,
p
)
+
c
a
l
(
m
+
1
,
r
,
m
x
l
s
o
n
,
m
p
l
s
o
n
)
cal(l,r,x,p)=cal(l,m,x,p)+cal(m+1,r,mx_{lson},mp_{lson})
cal(l,r,x,p)=cal(l,m,x,p)+cal(m+1,r,mxlson,mplson)。
后面那部分是可以预处理的。这样子我们的询问每次只会往一边走,复杂度是
O
(
l
o
g
n
)
O(logn)
O(logn) 的。
令
C
A
L
r
o
o
t
=
c
a
l
(
m
+
1
,
r
,
m
x
l
s
o
n
,
m
p
l
s
o
n
)
CAL_{root}=cal(m+1,r,mx_{lson},mp_{lson})
CALroot=cal(m+1,r,mxlson,mplson)。每次
p
u
s
h
u
p
pushup
pushup 的时候用
O
(
l
o
g
n
)
O(logn)
O(logn) 求
C
A
L
CAL
CAL 即可。
注意
b
b
b 数组的标记的处理就可以了。
总复杂度是
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n) 的。
代码如下
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void debug_out(){
cerr << endl;
}
template<typename Head, typename... Tail>
void debug_out(Head H, Tail... T){
cerr << ' ' << H;
debug_out(T...);
}
#ifdef local
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 55
#endif
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define lc rt << 1
#define rc rt << 1 | 1
const int N = 2e5 + 5;
int a[N], b[N];
int mx[N * 4], mp[N * 4], cal[N * 4], tag[N * 4], n;
void pushdown(int rt){
if(tag[rt]){
tag[lc] ^= 1;
tag[rc] ^= 1;
tag[rt] = 0;
}
}
int qryb(int l, int r, int rt, int p){
if(l == r) return (tag[rt] ^ b[l]);
pushdown(rt);
int m = l + r >> 1;
if(p <= m) return qryb(lson, p);
return qryb(rson, p);
}
int solve(int l, int r, int rt, int x, int p){
if(l == r){
if(mx[rt] >= x && (tag[rt] ^ b[l]) != qryb(1, n, 1, p)) return 1;
return 0;
}
pushdown(rt);
int m = l + r >> 1;
if(x > mx[lc]) return solve(rson, x, p);
return solve(lson, x, p) + cal[rt];
}
void pushup(int l, int r, int rt){
int m = l + r >> 1;
mx[rt] = max(mx[lc], mx[rc]);
if(mx[rt] == mx[lc]) mp[rt] = mp[lc];
if(mx[rt] == mx[rc]) mp[rt] = mp[rc];
cal[rt] = solve(rson, mx[lc], mp[lc]);
}
void build(int l, int r, int rt){
if(l == r){
mx[rt] = a[l], mp[rt] = l;
return;
}
int m = l + r >> 1;
build(lson);
build(rson);
pushup(l, r, rt);
}
void upd1(int l, int r, int rt, int p, int c){
if(l == r){
mx[rt] = c;
return;
}
pushdown(rt);
int m = l + r >> 1;
if(p <= m) upd1(lson, p, c);
else upd1(rson, p, c);
pushup(l, r, rt);
}
void upd2(int l, int r, int rt, int a, int b){
if(l >= a && r <= b){
tag[rt] ^= 1;
return;
}
pushdown(rt);
int m = l + r >> 1;
if(a <= m) upd2(lson, a, b);
if(b > m) upd2(rson, a, b);
pushup(l, r, rt);
}
tuple<int, int, int> query(int l, int r, int rt, int x, int p, int a, int b){
if(l >= a && r <= b){
if(mx[rt] < x) return make_tuple(0, x, p);
return make_tuple(solve(l, r, rt, x, p), mx[rt], mp[rt]);
}
pushdown(rt);
int m = l + r >> 1;
if(b <= m) return query(lson, x, p, a, b);
if(a > m) return query(rson, x, p, a, b);
auto p1 = query(lson, x, p, a, m);
int a1, a2;
tie(a1, x, p) = p1;
auto p2 = query(rson, x, p, m + 1, b);
tie(a2, x, p) = p2;
return make_tuple(a1 + a2, x, p);
}
int main() {
#ifdef local
freopen("../in.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++) cin >> b[i];
build(1, n, 1);
int q;
cin >> q;
for(int i = 1, o, l, r; i <= q; i++){
cin >> o >> l >> r;
if(o == 1){
a[l] = r;
upd1(1, n, 1, l, r);
}
else if(o == 2){
upd2(1, n, 1, l, r);
}
else{
auto t = query(1, n, 1, a[l], l, l, r);
int w, x, y;
tie(w, x, y) = t;
cout << w << '\n';
}
}
return 0;
}