Luogu P3258 松鼠的新家(樹鏈剖分+線段樹/樹狀陣列)
阿新 • • 發佈:2018-11-03
題面
題解
這種題目一看就是重鏈剖分裸題,還是區間修改,單點查詢,查詢之前在遍歷時要記一個\(delta\),因為這一次的起點就是上一次的終點,不需要放糖,所以可以用\(BIT\)來寫,但我寫完\(modify\)才反應過來,所以沒改了。
#include <cstdio> #include <cstring> #include <algorithm> using std::swap; const int N = 3e5 + 10; int n, a[N], siz[N], son[N], fa[N], dep[N]; int tim, dfn[N], top[N], delta[N]; int cnt, from[N], to[N << 1], nxt[N << 1]; int val[N << 2], add[N << 2]; inline void addEdge(int u, int v) { to[++cnt] = v, nxt[cnt] = from[u], from[u] = cnt; } void dfs(int u) { siz[u] = 1, dep[u] = dep[fa[u]] + 1; for(int i = from[u]; i; i = nxt[i]) { int v = to[i]; if(v == fa[u]) continue; fa[v] = u, dfs(v), siz[u] += siz[v]; if(siz[v] > siz[son[u]]) son[u] = v; } } void dfs(int u, int t) { dfn[u] = ++tim, top[u] = t; if(!son[u]) return ; dfs(son[u], t); for(int i = from[u]; i; i = nxt[i]) { int v = to[i]; if(v != fa[u] && v != son[u]) dfs(v, v); } } inline void pushup (int o, int lc, int rc) { val[o] = val[lc] + val[rc]; } inline void pushdown (int o, int lc, int rc, int len) { if(add[o]) { val[lc] += add[o] * (len - (len >> 1)); val[rc] += add[o] * (len >> 1); add[lc] += add[o], add[rc] += add[o], add[o] = 0; } } void modify (int ml, int mr, int k, int o = 1, int l = 1, int r = n) { if(l >= ml && r <= mr) { val[o] += k * (r - l + 1), add[o] += k; return ; } int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1; pushdown(o, lc, rc, r - l + 1); if(ml <= mid) modify(ml, mr, k, lc, l, mid); if(mr > mid) modify(ml, mr, k, rc, mid + 1, r); pushup(o, lc, rc); } int query(int qs, int o = 1, int l = 1, int r = n) { if(l == r && l == qs) return val[o]; int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1; pushdown(o, lc, rc, r - l + 1); if(qs <= mid) return query(qs, lc, l, mid); else return query(qs, rc, mid + 1, r); } inline void Path(int x, int y) { int fx = top[x], fy = top[y]; while(fx != fy) { if(dep[fx] >= dep[fy]) modify(dfn[fx], dfn[x], 1), x = fa[fx], fx = top[x]; else modify(dfn[fy], dfn[y], 1), y = fa[fy], fy = top[y]; } if(dfn[x] > dfn[y]) swap(x, y); modify(dfn[x], dfn[y], 1); } int main () { scanf("%d", &n); for(int i = 1; i <= n; ++i) scanf("%d", a + i); for(int i = 1, u, v; i < n; ++i) { scanf("%d%d", &u, &v); addEdge(u, v), addEdge(v, u); } dfs(1), dfs(1, 1); for(int i = 2; i <= n; ++i) Path(a[i - 1], a[i]), ++delta[a[i]]; for(int i = 1; i <= n; ++i) printf("%d\n", query(dfn[i]) - delta[i]); return 0; }