「学习笔记」树上差分

问了 阿丑 两道题的询问操作部分,发现我两次问的东西是一模一样的东西:树上差分。

一道是主席树题P3302 [SDOI2013]森林,一道是线段树合并P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并

\(x\)\(y\) 路径上的点进行操作时,找到 \(lca\)\(fa[lca]\) 。这里不妨操作是 \(+val\)

类似于差分数组的操作,对 \(x\)\(y\) 进行 \(+val\) ,对 \(lca\)\(fa[lca]\) 进行 \(-val\) 。然后再 pushup 上传结点信息。

下图中浅蓝色的“+1”表示 pushup 时通过边传递上来的信息

这样一来 \(x\)\(y\) 实现了 \(+1\)\(lca\) 实现了 \(+1+1-1=+1\)\(fa[lca]\) 实现了 \(+1-1=0\)

P3302 [SDOI2013]森林一题中的:

int query(int x,int y,int p1,int p2,int l,int r,int k){
    int mid=l+r>>1;
    int lsz=sum[lc[x]]+sum[lc[y]]-sum[lc[p1]]-sum[lc[p2]];//就是这句!
    if(l==r) return b[l];
    if(k<=lsz)
        return query(lc[x],lc[y],lc[p1],lc[p2],l,mid,k);
    else return query(rc[x],rc[y],rc[p1],rc[p2],mid+1,r,k-lsz);
}

main函数中询问操作的回答↓
query(rt[x],rt[y],rt[yyh],rt[st[yyh][0]],1,len,k);

以及P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并一题中的:

mian函数里↓
rt[x[i]]=upd(rt[x[i]],1,len,z[i],1);
rt[y[i]]=upd(rt[y[i]],1,len,z[i],1);
rt[yyh]=upd(rt[yyh],1,len,z[i],-1);
if(fa[yyh]) rt[fa[yyh]]=upd(rt[fa[yyh]],1,len,z[i],-1);

//之后有merge操作合并每个点与它儿子的权值线段树,实现了差分标记的上传

由于只是给自己留的一个记录,所以写的非常简略且例子也不是经典的树上差分例子。

posted @ 2021-07-01 15:44  Push_Y  阅读(42)  评论(0编辑  收藏  举报