题目对于二叉树的知识点的考察直接拉满
其实很容易发现对于只有 1,3 的序列是很容易维护的,但是同时要维护右儿子,需要清楚到底要维护什么
设当前序列已经有 x 个有效的右儿子,(有效的意思是没有被访问父节点的操作抵消掉)
那么其对答案的贡献值应该是
剩下的就是找到有多少个有效的右儿子即可,由于这个序列会构成一棵树
那么树的根,也就是深度最低的那个节点开始才记录有效的右儿子,不仅仅是右儿子,还有左儿子
既然要维护树的根,不妨将维护这个序列转化为维护树的根,与树的右子树的深度
这样 1,3 和 2 操作就联系了起来
树的数据成员有 : top 根的高度,cnt 右儿子的贡献,down 右子树的深度
建树的时候判断序列的值给对应的树赋值即可
更新操作为基本的线段树单点更新
询问操作比较麻烦,需要将多个序列的信息进行整合,当两个序列进行整合时:
- 如果当前序列的右子树的深度大于带加入序列根的深度时 : 那么只能抵消其右子树的一部分
- 否则当前序列的根节点的深度要更新,且右子树完全变为带加入序列的右子树
题目还要注意,带单点更新时,此节点的信息必须完全删除后再进行更新,因为更新节点的信息并不是可覆盖的
const int N=5e5+5;
int i,j,k;
int n,m;
int a[N];
struct Node
{
//int l,r;
int top,down; //树的根,树的右子树的最大深度
int cnt; //右儿子的贡献
#define lson id<<1
#define rson id<<1|1
Node(int a=0,int b=0,int c=0):top(a),down(b),cnt(c){}
//比较两棵树 b 是否能改变原树的右子树
Node operator + (const Node b)
{
Node ans;
if(b.top>=down){ //b 可以消除 a 区间顶点右子树的影响
ans=b;
ans.top=b.top-down+top;
} else{
ans.top=top;
ans.down=down+b.down-b.top;
ans.cnt=((cnt>>b.top)<<b.down)+b.cnt;
}
return ans;
}
void update(int x)
{
//不需要判 x 是否合法,题目已明确数据范围
top=down=cnt=0;
x==3?top=1:down=1,cnt=(x==2);
}
}t[N<<2];
void push_up(int id)
{
t[id]=t[lson]+t[rson];
}
void build(int l,int r,int id)
{
//t[id].l=l,t[id].r=r;
//t[id].top=t[id].down=0;
if(l==r){
t[id].update(a[l]);
//dbg(t[id].top);
//dbg(t[id].down);
}
else{
int mid=l+r>>1;
build(l,mid,lson);
build(mid+1,r,rson);
push_up(id);
}
}
void update(int pos,int val,int id,int l,int r)
{
//int l=t[id].l,r=t[id].r;
if(l==r) t[id].update(val);
else{
int mid=l+r>>1;
if(mid>=pos) update(pos,val,lson,l,mid);
else update(pos,val,rson,mid+1,r);
push_up(id);
}
}
Node query(int l,int r,int id,int L,int R)
{
//int L=t[id].l,R=t[id].r;
if(L>=l && r>=R) return t[id];
else{
int mid=L+R>>1;
Node ans;
if(mid>=l) ans=ans+query(l,r,lson,L,mid);
if(r>=mid+1) ans=ans+query(l,r,rson,mid+1,R);
//dbg(ans.top);
return ans;
}
}
int main()
{
//IOS;
while(~sddd(k,n,m)){
//k=(1<<k);
for(int i=1;i<=n;i++) sd(a[i]);
build(1,n,1);
int opt,x,y;
while(m--){
sd(opt);
if(opt==1){
ll s; sll(s);
sdd(x,y);
Node ans=query(x,y,1,1,n);
ll res=(max(s>>ans.top,1ll)<<ans.down)+ans.cnt;
pll(res);
} else{
sdd(x,y);
update(x,y,1,1,n);
}
}
}
//PAUSE;
return 0;
}