[洛谷P4092][HEOI2016/TJOI2016]樹
阿新 • • 發佈:2018-11-25
題目大意:給你一棵樹,有兩個操作:
- $C\;x:$給第$x$個節點打上標記
- $Q\;x:$詢問第$x$個節點的祖先中最近的打過標記的點(自己也是自己的祖先)
題解:樹剖,可以維護區間或,然後若一段區間為$0$則跳過,否則線上段樹上二分
卡點:二分部分多大了一個$=$,然後$MLE$
C++ Code:
#include <cstdio> #include <algorithm> #include <ctime> #include <cctype> #include <cstdlib> namespace __IO { namespace R { int x, ch; inline int read() { ch = getchar(); while (isspace(ch)) ch = getchar(); for (x = ch & 15, ch = getchar(); isdigit(ch); ch = getchar()) x= x * 10 + (ch & 15); return x; } inline char readc() { ch = getchar(); while (!isalpha(ch)) ch = getchar(); return static_cast<char> (ch); } } } using __IO::R::read; using __IO::R::readc; #define maxn 100010 int head[maxn], cnt; struct Edge { int to, nxt; } e[maxn << 1]; inline void add(int a, int b) { e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt; e[++cnt] = (Edge) {a, head[b]}; head[b] = cnt; } int n, m; int dfn[maxn], idx, fa[maxn], sz[maxn]; int son[maxn], top[maxn], dep[maxn], ret[maxn]; void dfs1(int u) { sz[u] = 1; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v != fa[u]) { dep[v] = dep[u] + 1; fa[v] = u; dfs1(v); if (!son[u] || sz[v] > sz[son[u]]) son[u] = v; sz[u] += sz[v]; } } } void dfs2(int u) { dfn[u] = ++idx, ret[idx] = u; int v = son[u]; if (v) top[v] = top[u], dfs2(v); for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v != son[u] && v != fa[u]) { top[v] = v; dfs2(v); } } } namespace SgT { bool V[maxn << 2]; int pos, L, R; void modify(int rt, int l, int r) { V[rt] = true; if (l == r) return ; int mid = l + r >> 1; if (pos <= mid) modify(rt << 1, l, mid); else modify(rt << 1 | 1, mid + 1, r); } void modify(int __pos) { pos = __pos; modify(1, 1, n); } bool res; void query(int rt, int l, int r) { if (L <= l && R >= r) return static_cast<void> (res |= V[rt]); int mid = l + r >> 1; if (L <= mid) query(rt << 1, l, mid); if (res) return ; if (R > mid) query(rt << 1 | 1, mid + 1, r); } bool query(int __L, int __R) { res = false; L = __L, R = __R; query(1, 1, n); return res; } int ans; void ask(int rt, int l, int r) { if (!V[rt]) return ; if (l == r) { if (!ans) ans = l; return ; } int mid = l + r >> 1; if (R > mid) ask(rt << 1 | 1, mid + 1, r); if (ans) return ; if (L <= mid) ask(rt << 1, l, mid); } int ask(int __L, int __R) { L = __L, R = __R; ans = 0; ask(1, 1, n); return ret[ans]; } } int query(int x) { while (top[x] != 1) { if (SgT::query(dfn[top[x]], dfn[x])) return SgT::ask(dfn[top[x]], dfn[x]); x = fa[top[x]]; } return SgT::ask(1, dfn[x]); } int main() { n = read(), m = read(); for (int i = 1, a, b; i < n; i++) { a = read(), b = read(); add(a, b); } dfs1(1); top[1] = 1; dfs2(1); SgT::modify(1); while (m --> 0) { char op = readc(); int x = read(); if (op == 'C') { SgT::modify(dfn[x]); } else { printf("%d\n", query(x)); } } return 0; }