1. 程式人生 > >[洛谷P4092][HEOI2016/TJOI2016]樹

[洛谷P4092][HEOI2016/TJOI2016]樹

題目大意:給你一棵樹,有兩個操作:

  1. $C\;x:$給第$x$個節點打上標記
  2. $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;
}