「學習筆記」樹上差分
阿新 • • 發佈:2021-07-01
問了 阿醜 兩道題的詢問操作部分,發現我兩次問的東西是一模一樣的東西:樹上差分。
一道是主席樹題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操作合併每個點與它兒子的權值線段樹,實現了差分標記的上傳
由於只是給自己留的一個記錄,所以寫的非常簡略且例子也不是經典的樹上差分例子。