乙個有點意思的樹鏈剖分的題。
題意:
一棵樹,有兩種操作:
①:在點v
vv放x
xx個蘑菇。
②:將起點變為vvv。
每次計算收集所有蘑菇的代價。
收集蘑菇的代價為,起點到所在蘑菇的路徑上的第一條邊的權值,也就是與起點直接相連的邊的權值。
做法:
選定11
1號節點為根節點,
考慮樹鏈剖分,對於更新操作,我們更新從v
−>
1v->1
v−>
1的所有重鏈上的蘑菇數量,在輕鏈與重鏈的連線處,直接統計輕鏈對當前節點的貢獻即可。
查詢時,我們只需要查詢重兒子上的蘑菇的數量然後乘上邊權,再加上當前節點的輕鏈對其貢獻(之前統計過的),然後再得到其父節點的連通塊的答案即可。
#include
using
namespace std;
typedef
long
long ll;
typedef pair pll;
const
int n =
1e6+10;
int head[n]
, to[n <<1]
, nex[n <<1]
, value[n <<1]
, cnt =1;
int n, m, fv[n]
;int dep[n]
, fa[n]
, sz[n]
, top[n]
, rk[n]
, id[n]
, son[n]
, tot;
ll sum, tree[n <<2]
, lazy[n <<2]
, num[n]
;pll ans[n]
;inline
void
add(
int x,
int y,
int w)
void
dfs1
(int rt,
int f)
dfs1
(to[i]
, rt)
; fv[to[i]
]= value[i]
; sz[rt]
+= sz[to[i]];
if(sz[son[rt]
]< sz[to[i]])
}}void
dfs2
(int rt,
int tp)
dfs2
(son[rt]
, tp)
;for
(int i = head[rt]
; i; i = nex[i]
)dfs2
(to[i]
, to[i]);
}}void
push_down
(int rt)
}void
update
(int rt,
int l,
int r,
int l,
int r,
int x)
push_down
(rt)
;int mid = l + r >>1;
if(l <= mid)
if(r > mid)
}ll query
(int rt,
int l,
int r,
int x)
push_down
(rt)
;int mid = l + r >>1;
if(x <= mid)
else
}void
solve
(int v,
int x)
}ll get_ans
(int v)
res +
= fv[son[v]
]* cur;
res +
= ans[v]
.first;
res +
= fv[v]
*(sum - cur - ans[v]
.second - num[v]);
return res;
}int
main()
dfs1(1
,0);
dfs2(1
,1);
scanf
("%d"
,&m)
;for
(int i =
1, op, v, x, rt =
1; i <= m; i++
)else
printf
("%lld\n"
,get_ans
(rt));
}return0;
}
LCA的樹鏈剖分實現
這篇本來是要在 樹鏈剖分小節 中寫的,但是我感覺這只是樹鏈剖分的乙個衍生物,所以另開了一篇,如果對樹鏈剖分部分還不是太了解,請看上面的鏈結。計算樹中兩個節點的最近公共祖先,我們一般有爬山法,tarjan離線演算法,或者是將lca轉換成rmq來解,這裡講一講一種新的求lca的演算法,它是基於樹鏈剖分的...
狐假虎威的樹鏈剖分
運算元據結構 線段樹 結束語 最近在做運輸計畫這道題時,發現要用數鏈剖分,於是就打算學學這個玩意兒。其實之前一直以為這個東西是個很複雜的東西,可能 看起來都很長。但是,學了之後,我才發現,這個東西很好懂,而且 之所以很長,也有乙個原因就是它需要使用乙個強大的資料結構 線段樹。線段樹的 其實並不算少,...
樹鏈剖分的學習理解
前言 本文僅為本人學習樹鏈剖分的理解和總結,有誤之處請大佬指點迷津。也有與其他部落格不同或矛盾之處。樹鏈剖分 顧名思義,將樹結構,剖分成鏈狀結構,然後將一條條的鏈拼接成線性結構,然後就可以通過線段樹 樹狀陣列等維護了。說白了就是在樹上,有些值不好維護,通過樹鏈剖分轉化成乙個序列,而序列就好維護了。樹...