線段樹合併
前置知識
權值線段樹,動態開點線段樹
簡單說明一下,權值線段樹就是以值域開的一棵線段樹,而動態開點就是因為值域過大導致線段樹開不下,於是開一棵殘疾的線段樹。
線段樹合併模板
例:給定兩個數列 \(a , b\) , 求 \(\sum a_i+b_i\)
當然我只是為了引出模板。
程式碼 ( \(x\) 表示第一棵線段樹 , \(y\) 為後者 , 我們將 \(y\) 樹直接加到 \(x\) 上)
CODE
template <typename T> void merge(T &x , T y , T l , T r) {
if (!x || !y) {
x = x + y ; return x + y ;
}
if (l == r) {
... // operation
return ;
}
int mid = (l + r) >> 1 ;
merge(t[x].lson , t[y].lson , l , mid) ;
merge(t[x].rson , t[y].rson , mid + 1 , r) ;
push_up(x) ;
}
signed main() {
...
// 呼叫
merge(Root[x] , Root[y] , 1 , Size) ;
}
例題
Vani有約會 luogu P4556 雨天的尾巴
$$luogu$$
我們可以考慮用樹上差分,最後在一個一個加起來,易證明正確性。
Code
CODE
#include <bits/stdc++.h>
#define Lv_Jiankai Clamp
#define log_N 21
using namespace std ;
const int N = 3e5 + 100 ;
const int Size = 1e5 ;
int read() {
int x = 0 , f = 1 ;
char c = getchar() ;
while (c < '0' || c > '9') {
if (c == '-') f = -f ;
c = getchar() ;
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0' ;
c = getchar() ;
}
return x * f ;
}
int n , m , root ; int depth[N] ;
int Query_father[N][21] ; int lg[N] ; int Root[N] ;
int answer[N] ;
class EDGE {
public:
int next , to ;
} e[N] ; int head[N] , cnt , tot ;
template <typename T> T Min(T a , T b) {
return a < b ? a : b ;
}
namespace SEGMENT_TREE {
class Segment_Dynamic_Opening_Point {
public:
int lson , rson , data , first_name ;
Segment_Dynamic_Opening_Point() {
lson = rson = data = first_name = 0 ;
}
} t[N * 80] ; int numbol = 0 ;
template <typename T> void push_up(T id) {
if (t[t[id].lson].data > t[t[id].rson].data) {
t[id].data = t[t[id].lson].data ;
t[id].first_name = t[t[id].lson].first_name ;
} else if (t[t[id].lson].data < t[t[id].rson].data) {
t[id].data = t[t[id].rson].data ;
t[id].first_name = t[t[id].rson].first_name ;
} else {
t[id].data = t[t[id].lson].data ;
t[id].first_name = Min(t[t[id].lson].first_name , t[t[id].rson].first_name) ;
}
}
template <typename T> void updata(T &id , T l , T r , T x , T v) {
if (!id) id = ++ numbol ;
if (l == r) {
t[id].data += v ; t[id].first_name = t[id].data ? l : 0 ;
return ;
}
int mid = (l + r) >> 1 ;
if (x <= mid) {
updata(t[id].lson , l , mid , x , v) ;
} else {
updata(t[id].rson , mid + 1 , r , x , v) ;
}
push_up(id) ;
}
template <typename T> void merge(T &x , T y , T l , T r) {
if (!x || !y) {
x = x + y ; return ;
}
if (l == r) {
t[x].data += t[y].data ;
t[x].first_name = t[x].data ? l : 0 ;
return ;
}
int mid = (l + r) >> 1 ;
merge(t[x].lson , t[y].lson , l , mid) ;
merge(t[x].rson , t[y].rson , mid + 1 , r) ;
push_up(x) ;
}
} using namespace SEGMENT_TREE ;
template <typename T> void add(T x , T y) {
cnt ++ ;
e[cnt].to = y ;
e[cnt].next = head[x] ;
head[x] = cnt ;
}
template <typename T> void dfs(T x , T fa) {
depth[x] = depth[fa] + 1 ;
Query_father[x][0] = fa ;
for (int j = 1 ; j <= lg[depth[x]] ; ++ j) {
Query_father[x][j] = Query_father[Query_father[x][j - 1]][j - 1] ;
}
for (int i = head[x] ; i ; i = e[i].next) {
int y = e[i].to ;
if (y != fa) {
dfs(y , x) ;
}
}
}
template <typename T> T LCA(T x , T y) {
if (depth[x] > depth[y]) swap(x , y) ;
for (int i = lg[depth[y]] ; i >= 0 ; -- i) {
int willer = Query_father[y][i] ;
if (depth[willer] >= depth[x]) y = willer ;
}
if (x == y) return x ;
for (int i = lg[depth[x]] ; i >= 0 ; -- i) {
if (Query_father[x][i] != Query_father[y][i]) {
x = Query_father[x][i] ; y = Query_father[y][i] ;
}
}
return Query_father[x][0] ;
}
template <typename T> void Dfs_Query(T x , T fa) {
for (int i = head[x] ; i ; i = e[i].next) {
int y = e[i].to ;
if (y != fa) {
Dfs_Query(y , x) ;
merge(Root[x] , Root[y] , 1 , Size) ;
}
}
answer[x] = t[Root[x]].first_name ;
}
signed main() {
#ifndef ONLINE_JUDGE
freopen("1.in" , "r" , stdin) ;
freopen("1.out", "w" ,stdout) ;
#endif
n = read() ; m = read() ;
for (int i = 2 ; i <= 3e5 ; ++ i) {
lg[i] = lg[i >> 1] + 1 ;
}
int x , y ;
for (int i = 1 ; i < n ; ++ i) {
x = read() ; y = read() ;
add(x , y) ; add(y , x) ;
}
root = 1 ;
dfs(root , 0) ;
int z ;
for (int i = 1 ; i <= m ; ++ i) {
x = read() ; y = read() ; z = read() ;
int ancestor = LCA(x , y) ;
updata(Root[x] , 1 , Size , z , 1) ;
updata(Root[y] , 1 , Size , z , 1) ;
updata(Root[ancestor] , 1 , Size , z , -1) ;
if (Query_father[ancestor][0]) {
updata(Root[Query_father[ancestor][0]] , 1 , Size , z , -1) ;
}
}
Dfs_Query(root , 0) ;
for (int i = 1 ; i <= n ; ++ i) {
cout << answer[i] << '\n' ;
}
}