Lazy Treap实现异常:懒标记失效导致子串反转功能出错
CSES「Substring Reversals」问题的Lazy Treap实现错误排查
我在解决CSES的「Substring Reversals」问题时,采用Lazy Treap实现,但懒标记机制未生效,运行结果错误。对比参考代码后未发现明显差异,我的代码如下:
#include <bits/stdc++.h> using namespace std; struct Node { int priority=rand(),sz=1; char value; bool flip=0; Node *l=nullptr, *r=nullptr; Node(char _value): value(_value){} }; using NodePtr = Node*; int get_sz(NodePtr t) { return t ? t->sz : 0; } void pull_sz(NodePtr t) { if(t) t->sz = get_sz(t->l) + get_sz(t->r) + 1; } void push_lz(NodePtr t){ if (t && t->flip){ t->flip = 0; swap(t->l,t->r); if (t->l) t->l->flip ^= 1; if (t->r) t->r->flip ^= 1; } } void split(NodePtr t, NodePtr &l, NodePtr &r, int k){ if (!t) { l = r = nullptr; return; } int rank = get_sz(t->l) + 1; push_lz(t); if(rank <= k) { l = t; split(l->r, l->r, r, k-rank); } else { r = t; split(r->l, l, r->l, k); } pull_sz(l); pull_sz(r); } void merge(NodePtr &t, NodePtr l, NodePtr r){ push_lz(l); push_lz(r); if(!l) t = r; else if(!r) t = l; else if (l->priority > r->priority){ t = l; merge(t->r, t->r, r); } else { t = r; merge(t->l, l, t->l); } pull_sz(t); } NodePtr find_by_order(NodePtr t, int k) { if(!t) return t; int lsz = get_sz(t->l); if(k == lsz) { return t; } else if(k < lsz) { return find_by_order(t->l, k); } else { return find_by_order(t->r, k-lsz-1); } } NodePtr build(const string& v, int lb, int rb) { if(lb == rb) { return new Node(v[lb]); } int mb = (lb+rb)/2; NodePtr l = build(v, lb, mb); NodePtr r = build(v, mb+1, rb); NodePtr t; merge(t, l, r); return t; } void output(NodePtr t) { if(!t) return; push_lz(t); output(t->l); cout << t->value; output(t->r); } int main(){ int n,t; string s; cin >> n >> t; cin >> s; NodePtr tr = build(s,0,n-1); while (t--){ int a,b; cin >> a >> b; a--;b--; NodePtr l,m,r; split(tr,l,m,a); split(m,m,r,b-a+1); if (m) m->flip ^= true; merge(tr,l,m); merge(tr,tr,r); } output(tr); }
运行以下测试输入:
5 2 ABCDE 1 5 1 4
得到的错误输出为:
ABCDE
这显然不符合预期,说明懒标记未在split操作中正确传递。我的split函数与参考代码功能相似,仅索引跟踪方式不同,请问实现中存在什么问题?
更新:已找到bug——split函数中push_lz与rank计算的顺序错误,应先执行push_lz再计算rank,因为push_lz可能改变与get_sz(t->l)相关的子树结构。
内容的提问来源于stack exchange,提问作者PlainXYZ
相关产品推荐
相关产品推荐

