此博文只用來記錄寫樹剖時個人錯誤(我寫的真是太好看了!)node
\(ps\):由於\(lfd\),我愛上了壓行ios
\(1.\)不要混淆變量名、函數名,由於這個\(WA\)過(好比在\(dfs1\)裏調用了\(dfs2\)……)
\(2.\)題目讓你取模就不要忘記取模,第一次交只有部分取模了致使只有\(30\)分,並且要隨時取模,隨時取模, 隨時取模!
\(3.\)全局變量初始值爲\(0\),但局部變量並非!!在線段樹的\(asksum\)部分我沒給\(ans\)賦初值,查錯查了好久
\(4.\)跳的時候是跳到鏈頂的父親節點那裏!不是跳到鏈頂!
\(5.\)查詢或修改樹上兩個點之間路徑的時候是查詢點之間的,因此一開始不須要用\(dfn[x]\),\(dfn[y]\),而查詢或者修改一個子樹的權值時,就要用到\(dfn[x]\)了,由於在第一遍\(dfs\)(我代碼裏的\(prepare\))以後,第二遍\(dfs\)就可以保證一棵子樹的\(dfn\)序是連續的,因此能夠直接用\(dfn[x]\)和\(dfn[x] + siz[x] - 1\)來修改和查詢這棵子樹的權值和(由於本身也是本身子樹的一員,因此要減一)git
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int A = 1e6 + 11; inline int read() { char c = getchar(); int x = 0, f = 1; for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1; for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48); return x * f; } int n, m, root, mod, w[A], pre[A]; struct node { int to, nxt; } e[A]; int head[A], cnt; inline void add_edge(int from, int to) { e[++cnt].to = to; e[cnt].nxt = head[from]; head[from] = cnt; } namespace Seg { #define lson rt << 1 #define rson rt << 1 | 1 struct tree { int l, r, w, lazy; } t[A]; inline void pushup(int rt) { t[rt].w = (t[lson].w + t[rson].w) % mod; } inline void pushdown(int rt) { t[lson].lazy = (t[lson].lazy + t[rt].lazy) % mod; t[rson].lazy = (t[rson].lazy + t[rt].lazy) % mod; t[lson].w += (t[lson].r - t[lson].l + 1) * t[rt].lazy; t[lson].w %= mod; t[rson].w += (t[rson].r - t[rson].l + 1) * t[rt].lazy; t[rson].w %= mod; t[rt].lazy = 0; return; } void build(int rt, int l, int r) { t[rt].l = l, t[rt].r = r; if(l == r) { t[rt].w = w[pre[l]] % mod; return; } int mid = (l + r) >> 1; build(lson, l, mid), build(rson, mid + 1, r); pushup(rt); return; } void update(int rt, int l, int r, int val) { if(l <= t[rt].l && t[rt].r <= r) { t[rt].lazy += val % mod; t[rt].lazy %= mod; t[rt].w += (t[rt].r - t[rt].l + 1) * val % mod; t[rt].w %= mod; return; } if(t[rt].lazy) pushdown(rt); int mid = (t[rt].l + t[rt].r) >> 1; if(l <= mid) update(lson, l, r, val); if(r > mid) update(rson, l, r, val); pushup(rt); return; } int asksum(int rt, int l, int r) { if(l <= t[rt].l && t[rt].r <= r) { return t[rt].w % mod; } if(t[rt].lazy) pushdown(rt); int mid = (t[rt].l + t[rt].r) >> 1, ans = 0; if(l <= mid) ans += asksum(lson, l, r); if(r > mid) ans += asksum(rson, l, r); return ans; } } int dfn[A], top[A], siz[A], son[A], fa[A], tot, dep[A]; void prepare(int now, int fr) { siz[now] = 1, fa[now] = fr, dep[now] = dep[fr] + 1; for(int i = head[now]; i; i = e[i].nxt) { int to = e[i].to; if(to == fr) continue; prepare(to, now); siz[now] += siz[to]; if(siz[to] > siz[son[now]]) son[now] = to; } } void dfs(int now, int tp) { dfn[now] = ++tot, pre[tot] = now, top[now] = tp; if(son[now]) dfs(son[now], tp); for(int i = head[now]; i; i = e[i].nxt) { int to = e[i].to; if(to == son[now] || to == fa[now]) continue; dfs(to, to); } } void update(int x, int y, int val) { while(top[x] != top[y]) { if(dfn[top[x]] < dfn[top[y]]) swap(x, y); Seg::update(1, dfn[top[x]], dfn[x], val); x = fa[top[x]]; } if(dep[x] > dep[y]) swap(x, y); Seg::update(1, dfn[x], dfn[y], val); return; } int ask(int x, int y) { int ans = 0; while(top[x] != top[y]) { if(dfn[top[x]] < dfn[top[y]]) swap(x, y); ans += Seg::asksum(1, dfn[top[x]], dfn[x]), ans %= mod; x = fa[top[x]]; } if(dep[x] > dep[y]) swap(x, y); ans += Seg::asksum(1, dfn[x], dfn[y]), ans %= mod; return (ans % mod + mod) % mod; } int main() { n = read(), m = read(), root = read(), mod = read(); for(int i = 1; i <= n; i++) w[i] = read() % mod; for(int i = 1; i < n; i++) { int x = read(), y = read(); add_edge(x, y), add_edge(y, x); } prepare(root, 0); dfs(root, root); Seg::build(1, 1, n); int opt, x, y, z; while(m--) { opt = read(); if(opt == 1) x = read(), y = read(), z = read() % mod, update(x, y, z); if(opt == 2) x = read(), y = read(), cout << ask(x, y) % mod << '\n'; if(opt == 3) x = read(), z = read(), Seg::update(1, dfn[x], dfn[x] + siz[x] - 1, z); if(opt == 4) x = read(), cout << Seg::asksum(1, dfn[x], dfn[x] + siz[x] - 1) % mod << '\n'; } }