对两颗树分别考虑.
对于第一颗树,考虑对每条链上双指针选择连续的节点(显然只有在同一条链上的点才能互为),用deque维护方便
对于第二颗树,n个点选择k个点互不为祖先,可以树剖+线段树维护,每次选择一个节点后对其所有子节点染色,判断节点是否和其他节点冲突只需要判断节点的子树下的最大值是不是0即可.
const int maxn = 3e5 + 7;
int n, t, m;
inline int read() {
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
vector<int> mp[maxn], mpz[maxn];
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
int dep[maxn], siz[maxn], fa[maxn], son[maxn];
int top[maxn], dfn[maxn], rnk[maxn], cnt;
#define ll int
struct tree {
struct Node {
ll l, r, lazy, mx;
void updata(ll val) {
lazy += val;
mx += val;
}
} node[maxn * 400];
void push_up(ll id) {
node[id].mx = max(node[id << 1].mx, node[id << 1 | 1].mx);
}
void push_down(ll id) {
ll lazy = node[id].lazy;
if (lazy) {
node[id << 1].updata(lazy);
node[id << 1 | 1].updata(lazy);
node[id].lazy = 0;
}
}
void build(ll id, ll l, ll r) {
node[id].l = l, node[id].r = r;
node[id].lazy = 0;
if (l == r) {
node[id].mx = 0;
} else {
ll mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
push_up(id);
}
}
ll query_max(ll id, ll L, ll R) {
ll l = node[id].l, r = node[id].r;
if (L <= l && r <= R)
return node[id].mx;
else {
push_down(id);
ll mid = (l + r) >> 1;
ll res = 0;
if (L <= mid) res = max(res, query_max(id << 1, L, R));
if (mid < R) res = max(res, query_max(id << 1 | 1, L, R));
return res;
}
}
void updata(ll id, ll L, ll R, ll k) { //将[l,r]区间的每个数加上k
ll l = node[id].l, r = node[id].r;
if (L <= l && r <= R) {
node[id].updata(k);
} else {
ll mid = (l + r) >> 1;
push_down(id);
if (L <= mid) updata(id << 1, L, R, k);
if (mid < R) updata(id << 1 | 1, L, R, k);
push_up(id);
}
}
} tr;
void tree_update(int p, int x) {
tr.updata(1, dfn[p], dfn[p] + siz[p] - 1, x);
}
int tree_max(int u) {
return tr.query_max(1, dfn[u], dfn[u] + siz[u] - 1);
}
void dfs(int u) {
siz[u] = 1;
son[u] = -1;
for (auto v : mp[u]) {
if (dep[v]) continue;
dep[v] = dep[u] + 1;
fa[v] = u;
dfs(v);
siz[u] += siz[v];
if (son[u] == -1 || siz[v] > siz[son[u]])
son[u] = v;
}
}
void dfs(int u, int tp) {
if (cnt >= n)
return;
top[u] = tp;
dfn[u] = ++cnt;
rnk[cnt] = u;
if (son[u] == -1) return;
dfs(son[u], tp);
for (auto v : mp[u])
if (v != son[u] && v != fa[u])
dfs(v, v);
}
void tree_init(int o = 1) {
dep[o] = 1;
dfn[o] = 1;
dfs(o);
dfs(o, o);
}
int ans = 0;
void init() {
ans = cnt = 0;
tr.build(1, 1, n);
for (int i = 1; i <= n + 5; i++)
mp[i].clear(), mpz[i].clear();
memset(dep, 0, sizeof dep);
}
void dfs(int u, int f, deque<int> &que) {
ans = max(ans, (int) que.size());
for (auto v:mpz[u]) {
if (v == f) continue;
deque<int> nxque = que, org;
nxque.push_back(v);
while (tree_max(v)) {
tree_update(nxque.front(), -1);
org.push_back(nxque.front());
nxque.pop_front();
}
tree_update(v, 1);
dfs(v, u, nxque);
tree_update(v, -1);
while (org.size())
tree_update(org.front(), 1), org.pop_front();
}
}
void solve() {
t = read();
while (t--) {
n = read();
init();
for (int i = 1, u, v; i < n; i++) {
u = read(), v = read();
mpz[u].push_back(v), mpz[v].push_back(u);
}
for (int i = 1, u, v; i < n; i++) {
u = read(), v = read();
mp[u].push_back(v), mp[v].push_back(u);
}
tree_init();
deque<int> qe;
qe.push_back(1);
tree_update(1, 1);
dfs(1, 0, qe);
printf("%d\n", ans);
}
}
(写了那么多树剖+线段树终于ac了一道题..不过犯病wa了好多发