1. 程式人生 > 其它 >「學習筆記」樹上差分

「學習筆記」樹上差分

問了 阿醜 兩道題的詢問操作部分,發現我兩次問的東西是一模一樣的東西:樹上差分。

一道是主席樹題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操作合併每個點與它兒子的權值線段樹,實現了差分標記的上傳

由於只是給自己留的一個記錄,所以寫的非常簡略且例子也不是經典的樹上差分例子。