题目
长度为的数组(n<=18)a[],保证任意时刻ai<=1e9,
维护q(q<=1e5)次操作,操作分四种,
1 x k 把ax替换为k
2 k 对每个长度为的区间进行区间反转
3 k 对两两长度为且相邻的区间进行交换
4 l r 询问区间[l,r]的和
思路来源
zbw代码、willingox代码
https://blog.csdn.net/Code92007/article/details/82710068 感觉有翻转单点的影子
题解1
考虑按层打reverse和swap标记,
查询的时候寻找查询区间的真正位置,
比如,pos在一个区间反转的[l,r]区间内的真实位置是其镜像,r-(pos-l)
比如,ql<=mid,但[l,r]发生过左右子树交换,则ql的真实位置为ql+len,
即原先在[l,mid]中,现在在[mid+1,r]中对应位置,len为mid-l+1
按是否完整包含在左/右子树中,拆成三种情况,
对应左右子树是否发生过交换,讨论六种情况
题解2
每一个节点维护一个18位的标记,
第k位表示深度为第k层的标记,在这个点中,有没有下放给儿子,
这里考虑到2、3操作的k一致,k从底往上单增
注意到,reverse标记相当于一个要释放到底层的左右子树交换标记,
因为1 2 3 4仅交换左右子树是3 4 1 2的效果,
需要再对3 4和1 2 分别做子树交换,才能做到4 3 2 1的区间翻转效果
而显然,swap标记下放一层即可,1 2 3 4交换之后,就是3 4 1 2
每个点,考虑这层需不需要发生子树交换时,只需检查自己那层对应的那一位即可,
标记既代表了这个操作还没有对左右子树进行交换,也代表了还没有下放给左右儿子
代码1
#include <bits/stdc++.h>
using namespace std;
const int N=(1<<18)+5;
typedef long long ll;
int n,q,op,x,y,rev[20],swp[20];
struct segtree{
int n;
struct node{int ls,rs,dep;ll v;}e[N<<2];
#define ls(p) e[p].ls
#define rs(p) e[p].rs
#define d(p) e[p].dep
#define v(p) e[p].v
void up(int p){v(p)=v(ls(p))+v(rs(p));}
void bld(int p,int l,int r){
if(l==r){scanf("%lld",&(v(p)));d(p)=0;return;}
int mid=l+r>>1;
bld(ls(p)=(p<<1),l,mid);
bld(rs(p)=(p<<1|1),mid+1,r);
d(p)=d(ls(p))+1;
up(p);
}
void init(int _n){n=_n;bld(1,1,n);}
void chg(int p,int l,int r,int x,ll v){
if(rev[d(p)]){
x=r-(x-l);
}
if(l==r){v(p)=v;return;}
int mid=(l+r)/2,len=mid-l+1;
if(swp[d(p)]){
if(x<=mid)x+=len;
else x-=len;
}
if(x<=mid)chg(ls(p),l,mid,x,v);
else chg(rs(p),mid+1,r,x,v);
up(p);
}
ll cnt(int p,int l,int r,int ql,int qr){
if(rev[d(p)]){
ql=r-(ql-l);
qr=r-(qr-l);
swap(ql,qr);
}
if(ql<=l && r<=qr)return v(p);
int mid=(l+r)/2,len=mid-l+1;
ll res=0;
if(swp[d(p)]){
if(qr<=mid){
return cnt(rs(p),mid+1,r,ql+len,qr+len);
}
else if(ql>mid){
return cnt(ls(p),l,mid,ql-len,qr-len);
}
else{
return cnt(ls(p),l,mid,l,qr-len)+cnt(rs(p),mid+1,r,ql+len,r);
}
}
else{
if(qr<=mid){
return cnt(ls(p),l,mid,ql,qr);
}
else if(ql>mid){
return cnt(rs(p),mid+1,r,ql,qr);
}
else{
return cnt(ls(p),l,mid,ql,mid)+cnt(rs(p),mid+1,r,mid+1,qr);
}
}
}
}seg;
int main(){
scanf("%d%d",&n,&q);
n=1<<n;
seg.init(n);
while(q--){
scanf("%d%d",&op,&x);
if(op==1){
scanf("%d",&y);
seg.chg(1,1,n,x,y);
}
else if(op==2){
rev[x]^=1;
}
else if(op==3){
swp[x+1]^=1;
}
else{
scanf("%d",&y);
printf("%lld\n",seg.cnt(1,1,n,x,y));
}
}
return 0;
}
代码2
#include <bits/stdc++.h>
using namespace std;
const int N=(1<<18)+5;
typedef long long ll;
int n,q,op,x,y;
struct segtree{
int n;
struct node{int ls,rs,rev,swp,dep;ll v;}e[N<<2];
#define ls(p) e[p].ls
#define rs(p) e[p].rs
#define d(p) e[p].dep
#define v(p) e[p].v
#define re(p) e[p].rev
#define sw(p) e[p].swp
void up(int p){v(p)=v(ls(p))+v(rs(p));}
void bld(int p,int l,int r){
re(p)=sw(p)=0;
if(l==r){scanf("%lld",&(v(p)));d(p)=0;return;}
int mid=l+r>>1;
bld(ls(p)=(p<<1),l,mid);
bld(rs(p)=(p<<1|1),mid+1,r);
d(p)=d(ls(p))+1;
up(p);
}
void psd(int p){
if(re(p)){
if(re(p)&(1<<d(p))){
swap(ls(p),rs(p));
re(ls(p))^=(1<<(d(p)-1));
re(rs(p))^=(1<<(d(p)-1));
}
re(ls(p))^=re(p);
re(rs(p))^=re(p);
re(p)=0;
}
if(sw(p)){
if(sw(p)&(1<<d(p))){
swap(ls(p),rs(p));
}
sw(ls(p))^=sw(p);
sw(rs(p))^=sw(p);
sw(p)=0;
}
}
void init(int _n){n=_n;bld(1,1,n);}
void chg(int p,int l,int r,int x,ll v){
if(l==r){v(p)=v;return;}
psd(p);
int mid=(l+r)/2;
if(x<=mid)chg(ls(p),l,mid,x,v);
else chg(rs(p),mid+1,r,x,v);
up(p);
}
ll cnt(int p,int l,int r,int ql,int qr){
if(ql<=l && r<=qr)return v(p);
psd(p);
int mid=(l+r)/2;
ll res=0;
if(ql<=mid)res+=cnt(ls(p),l,mid,ql,qr);
if(qr>mid)res+=cnt(rs(p),mid+1,r,ql,qr);
return res;
}
}seg;
int main(){
scanf("%d%d",&n,&q);
n=1<<n;
seg.init(n);
while(q--){
scanf("%d%d",&op,&x);
if(op==1){
scanf("%d",&y);
seg.chg(1,1,n,x,y);
}
else if(op==2){
seg.e[1].rev^=(1<<x);
}
else if(op==3){
seg.e[1].swp^=(1<<(x+1));
}
else{
scanf("%d",&y);
printf("%lld\n",seg.cnt(1,1,n,x,y));
}
}
return 0;
}