题目
[CodeForces 1401F] Reverse and Swap
分析
直接对序列建线段树,Replace 和 Sum 是基本操作。首先可以发现 Reverse 操作是将某一层以及其下面的所有节点左右儿子交换,Swap 操作是将某一层的所有节点左右儿子互换。如果直接对每个节点开懒标记的话,PushDown
操作十分困难。发现一次操作实际上是改变的一层的状态,因此只需要对每层开一个标记表示该层的每个节点是否需要互换左右儿子即可。
代码
#include <bits/stdc++.h>
int Read() {
int x = 0; char c = getchar();
while (c < '0' || c > '9')
c = getchar();
while (c >= '0' && c <= '9')
x = x * 10 + (c ^ 48), c = getchar();
return x;
}
typedef long long LL;
const int MAXN = 18;
int N, M, Q, A[(1 << MAXN) + 5];
#define lch ((u << 1) | Rev[d])
#define rch ((u << 1) | (Rev[d] ^ 1))
int Rev[MAXN + 5];
LL Sum[4 * (1 << MAXN) + 5];
void PushUp(int u, int d) {
Sum[u] = Sum[lch] + Sum[rch];
}
void Build(int u, int l, int r, int d) {
if (l == r) {
Sum[u] = A[l];
return;
}
int mid = (l + r) >> 1;
Build(lch, l, mid, d + 1);
Build(rch, mid + 1, r, d + 1);
PushUp(u, d);
}
void Modify(int u, int l, int r, int p, int val, int d) {
if (l == r) {
Sum[u] = val;
return;
}
int mid = (l + r) >> 1;
if (p <= mid) Modify(lch, l, mid, p, val, d + 1);
else Modify(rch, mid + 1, r, p, val, d + 1);
PushUp(u, d);
}
LL Query(int u, int l, int r, int lft, int rgt, int d) {
if (lft <= l && r <= rgt)
return Sum[u];
int mid = (l + r) >> 1; LL ret = 0;
if (lft <= mid) ret = Query(lch, l, mid, lft, rgt, d + 1);
if (rgt >= mid + 1) ret += Query(rch, mid + 1, r, lft, rgt, d + 1);
return ret;
}
#undef lch
#undef rch
int main() {
N = 1 << (M = Read()), Q = Read();
for (int i = 1; i <= N; i++)
A[i] = Read();
Build(1, 1, N, 0);
while (Q--) {
int opt = Read();
if (opt == 1) {
int x = Read(), k = Read();
Modify(1, 1, N, x, k, 0);
}
else if (opt == 2) {
int k = Read();
for (int i = 1; i <= k; i++)
Rev[M - i] ^= 1;
}
else if (opt == 3) {
int k = Read();
Rev[M - k - 1] ^= 1;
}
else {
int l = Read(), r = Read();
printf("%lld\n", Query(1, 1, N, l, r, 0));
}
}
return 0;
}