對兩顆樹分別考慮.
對於第一顆樹,考慮對每條鏈上雙指針選擇連續的節點(顯然只有在同一條鏈上的點才能互為),用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了好多發