浅谈左偏树的pop操作
void pop(int x){
S[x].val = -1;
S[ls].rt = ls, S[rs].rt = rs;
S[x].rt = merge(ls, rs);
}
while(S[get(u)].sum > m) pop(get(u));
这是我一开始写的pop操作,和花学的。乍一看似乎没什么问题。但是当我去写 $P1552 [APIO2012] 派遣 $ 的时候我才发现不对劲 WA。 我先是看了眼题解,但是他们大多都是
int pop(int x) {
S[x].sum = S[x].val = S[x].siz = 0;
S[ls].rt = ls, S[rs].rt = rs;
return merge(ls, rs);
}
while(S[S[u].rt].sum > m )
S[u].rt = pop(S[u].rt);
这种不友好写法(就没有不返回值写法的吗)。
于是我开始疯狂调试之路。
在经历了整整一页的艰苦奋斗,我最终发现了问题
while(S[get(u)].sum > m) pop(get(u));
上述代码在进行 $pop$ 操作时,当弹出一个点后,其儿子与新根会有断层。 即 $pop$ 中 $ls$ 和 $rs$ 分别指向了自己,而新的根是 $ls$ 与 $rs$ 中的其中一个。假定落于 $ls$, 如果 $u$ 处于 $rs$。 则一次 $pop$ 操作之后再次进行 $get(u)$ 时,只能找到 $rs$ 而非新根 $ls$。 综上我给出我改过之后的 $pop$ 操作。
void pop(int x)
{
S[x].sum = S[x].val = S[x].siz = 0;
S[x].rt = S[ls].rt = S[rs].rt = merge(ls, rs);
}

浙公网安备 33010602011771号