CF1401F Reverse and Swap
非常抽象线段树,使我的大脑旋转。
考虑到建出的线段树一定是完全二叉树,且翻转或交换的区间一定满足都在一棵子树内,我们记 \(rev_{dep}\) 表示第 \(dep\) 层的左右子树是否交换(层数的定义是:从叶子往上,从 \(1\) 一直到 \(n + 1\) 层)。发现操作 \(3\) 等价于只交换第 \(k + 1\) 层,操作 \(2\) 等价于交换第 \(1 \sim k\) 层。(就是说翻转可以靠多次分治并从中点处左右交换实现)
现在考虑怎么快速实现交换。其实不用真的把整棵子树都交换,只需要交换左右儿子的编号就可以了。
时间复杂度 \(O(qn)\)。
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l); i <= (r); ++ i)
#define G(i,r,l) for(int i(r); i >= (l); -- i)
#define int ll
using namespace std;
using ll = long long;
char buf[100], *p1 = buf, *p2 = buf;
inline int gc(){
return (p1 == p2) && (p2 = (p1 = buf) + fread(buf, 1, 100, stdin), p1 == p2) ? EOF : *p1 ++;
}
inline int rd(){
int x = 0;
char ch;
while(!isdigit(ch = gc()));
do x = (x << 3) + (x << 1) + (ch ^ 48); while(isdigit(ch = gc()));
return x;
}
const int N = 300000;
int sum[N * 4];
bool rev[25]; // 打给自己, 且自己还没执行
int n, m, q;
void pushup(int u){
sum[u] = sum[u * 2] + sum[u * 2 + 1];
}
void update(int u, int l, int r, int x, int val, int dep){
if(l == r){
sum[u] = val;
return ;
}
int mid = (l + r) / 2;
if(rev[dep - 1]){
if(x <= mid) update(u * 2 + 1, l, mid, x, val, dep - 1);
else update(u * 2, mid + 1, r, x, val, dep - 1);
}
else{
if(x <= mid) update(u * 2, l, mid, x, val, dep - 1);
else update(u * 2 + 1, mid + 1, r, x, val, dep - 1);
}
pushup(u);
}
int query(int u, int l, int r, int x, int y, int dep){
if(l >= x && r <= y){
return sum[u];
}
int mid = (l + r) / 2, ret = 0;
if(rev[dep - 1]){
if(x <= mid) ret += query(u * 2 + 1, l, mid, x, y, dep - 1);
if(y > mid) ret += query(u * 2, mid + 1, r, x, y, dep - 1);
}
else{
if(x <= mid) ret += query(u * 2, l, mid, x, y, dep - 1);
if(y > mid) ret += query(u * 2 + 1, mid + 1, r, x, y, dep - 1);
}
pushup(u);
return ret;
}
signed main(){
n = rd(), q = rd();
m = 1 << n;
F(i, 1, m){
int x = rd();
update(1, 1, m, i, x, n + 1);
}
while(q --){
int opt = rd();
if(opt == 1){
int x = rd(), k = rd();
update(1, 1, m, x, k, n + 1);
}
else if(opt == 2){
int k = rd();
if(k == 0) continue;
F(i, 1, k) rev[i] ^= 1;
}
else if(opt == 3){
int k = rd();
rev[k + 1] ^= 1;
}
else{
int l = rd(), r = rd();
int ret = query(1, 1, m, l, r, n + 1);
printf("%lld\n", ret);
}
}
return 0;
}

浙公网安备 33010602011771号