有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個
操作,分為三種:
操作 1 :把某個節點 x 的點權增加 a 。
操作 2 :把某個節點 x 為根的子樹中所有點的點權都增加 a 。
操作 3 :詢問某個節點 x 到根的路徑中所有點的點權和。
樹鏈剖分後,節點x及其子樹節點會在一段連續的區間內,用線段樹維護區間和就可以了。注意如果是求根節點到根節點的,及1--1的,那麼直接輸出根節點的值就可以了,dfs2也要注意,當s==e的時候,tmp要加上根節點的值。
#include #include #include #include #include using namespace std;
typedef long long ll;
const int n = 1e5+5;
int n, m, cnt, tot;
int fa[n], dep[n], size[n], son[n], top[n], in[n], out[n], num[n], head[2*n];
ll value[n];
struct edge edge[2*n];
struct node tr[n<<2];
void add(int a, int b)
void dfs1(int d, int f, int u) // d:深度,f:父節點,u:當前節點
}void dfs2(int u, int tp) // u:當前節點,tp:鏈的頂端節點
out[u] = tot;
}void pushup(int m)
void pushdown(int m)
}void build(int m, int l, int r)
int mid = (l + r) >> 1;
build(m<<1, l, mid);
build(m<<1|1, mid + 1, r);
pushup(m);
}void change(int m, int id, ll val)
pushdown(m);
int mid = (tr[m].l + tr[m].r) >> 1;
if(id <= mid) change(m<<1, id, val);
else change(m<<1|1, id, val);
pushup(m);
}void updata(int m, int l, int r, ll val)
pushdown(m);
int mid = (tr[m].l + tr[m].r) >> 1;
if(l <= mid) updata(m<<1, l, r, val);
if(r > mid) updata(m<<1|1, l, r, val);
pushup(m);
}ll ask(int m, int l, int r)
ll find(int s, int e)
tmp += ask(1, in[fs], in[s]);
s = fa[fs];
fs = top[s];
} if(s == e) return tmp + ask(1, in[s], in[s]); // 當s==e時,說明現在s在根節點,要加上根節點的值
if(dep[s] > dep[e]) swap(s, e);
return tmp + ask(1, in[s], in[e]);
}int main()
dfs1(1, 0, 1);
dfs2(1, 1);
build(1, 1, n);
while(m--)
else if(op == 2)
else
}return 0;
}
LCA 樹鏈剖分 線段樹
給出乙個 n 個節點的有根樹 編號為 0 到 n 1 根節點為 0 乙個點的深度定義為這個節點到根的距離 1 設 dep i 表示點 i 的深度,lca i,j 表示 i 與 j 的最近公共祖先。有 q 次詢問,每次詢問給出 l,r,z 求 dep lca i,z 即,求在 l,r 區間內的每個節點...
HAOI2015 樹上操作 樹鏈剖分
1963.haoi2015 樹上操作 有一棵點數為n的樹,以點1為根,且樹點有權值。然後有m個操作,分為三種 操作1 把某個節點x的點權增加a。操作2 把某個節點x為根的子樹中所有點的點權都增加a。操作3 詢問某個節點x到根的路徑中所有點的點權和。第一行兩個整數n,m,表示點數和運算元。接下來一行n...
HAOI2015 樹上操作 樹鏈剖分
有一棵點數為n的樹,以點1為根,且樹點有權值。然後有m個操作,分為三種 操作1 把某個節點x的點權增加a。操作2 把某個節點x為根的子樹中所有點的點權都增加a。操作3 詢問某個節點x到根的路徑中所有點的點權和。第一行兩個整數n,m,表示點數和運算元。接下來一行n個整數,表示樹中節點的初始權值。接下來...