two 题解
一、题目:
二、思路:
这道题的思路其实也很简单,但就是想不到。
我们考虑题目中的限制“编号为 \(x,y\) 的两个顶点有且只有一个同时在顶点 \(p\) 的子树与顶点 \(q\) 的子树里”,看到这样的限制就应该想到 DFS 序或者其他能将子树包含关系转化到序列包含问题的做法。
对于这道题,我们采用欧拉序。并设蓝树中点 \(x\) 开始访问的时间戳为 \(in[x]\),访问结束的时间戳为 \(ou[x]\)。
对于一条在红树上的边 \((x,y)\),设 \(u=\min\{in[x],in[y]\},v=\max\{in[x],in[y]\}\),不妨设 \(p\) 是 \(q\) 的父亲,则 \((x,y)\) 对 \((p,q)\) 有害当且仅当:
\[in[q]\leq u \leq ou[q] \and v > ou[q]
\]
或
\[in[q]\leq v\leq ou[q]\and u < in[q]
\]
所以我们考虑使用线段树。建立两棵线段树 \(T_1,T_2\)。
- \(T_1\) 以每条边的 \(u\) 作为下标,节点 \((L,R)\)上存储 \(L\leq u\leq R\) 的那些边,并按 \(v\) 从小到大的顺序存储。
- \(T_2\) 以每条边的 \(v\) 作为下标,节点 \((L,R)\) 上存储 \(L\leq v\leq R\)的那些边,并按 \(u\) 从大到小的顺序存储。
对于一条已经在上一轮被删除的边 \((p,q)\),如何查询有多少边对它有害呢?
- 在 \(T_1\) 中所有满足 \(in[q]\leq L\leq R\leq ou[q]\) 的节点上,删除所有 \(v>ou[q]\) 的边。
- 在 \(T_2\) 中所有满足 \(in[q]\leq L\leq R\leq ou[q]\) 的节点上,删除所有 \(u<in[q]\) 的边。
这样做的复杂度是多少呢?
对于一条边,它最多会在 \(O(\log_2 n)\) 个节点中出现过,所以总复杂度是 \(O(n\log_2n)\)。
三、注意:
我们不能在线段树内部的每个节点对边进行排序,这样会使复杂度变为 \(O(n\log_2^2n)\)。本来常数就很大,这样干会超时。
每条边可能不止被“删”一次,所以需要在每条边上打标记,如果已经被删就不需要再管它了。
四、代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
#define FILEIN(s) freopen(s".in", "r", stdin)
#define FILEOUT(s) freopen(s".out", "w", stdout)
inline int read(void) {
int x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return f * x;
}
const int maxn = 200005;
int n, head[maxn][2], tot;
int in[maxn][2], ou[maxn][2], dfn;
int u[maxn][2], v[maxn][2];
bool tag[maxn][2];
struct Edge {
int y, next, id;
Edge() {}
Edge(int _y, int _next, int _id) : y(_y), next(_next), id(_id) {}
}e[maxn << 2];
struct Pair {
int x, y, id;
Pair() {}
Pair(int _x, int _y, int _id) : x(_x), y(_y), id(_id) {}
}edges[2][maxn];
vector<int>now, cpy;
inline void connect(int x, int y, int id, int k) {
e[++tot] = Edge(y, head[x][k], id);
head[x][k] = tot;
}
void pre(int x, int fa, int k) {
in[x][k] = ++dfn;
for (int i = head[x][k]; i; i = e[i].next) {
int y = e[i].y;
if (y == fa) continue;
pre(y, x, k);
}
ou[x][k] = ++dfn;
}
struct Tr1 {
#define lson (o << 1)
#define rson (o << 1 | 1)
vector<int>nodes[maxn << 4];
void insert(int o, int l, int r, int q, int id) {
if (l <= q && q <= r) nodes[o].push_back(id);
if (l == r) return;
int mid = (l + r) >> 1;
if (q <= mid) insert(lson, l, mid, q, id);
else insert(rson, mid + 1, r, q, id);
}
void del(int o, int l, int r, int ql, int qr, bool k) {
if (ql <= l && r <= qr) {
while (nodes[o].size() && v[nodes[o].back()][k] > qr) {
if (tag[nodes[o].back()][k])
now.push_back(nodes[o].back());
tag[nodes[o].back()][k] = false;
nodes[o].pop_back();
}
return;
}
int mid = (l + r) >> 1;
if (ql <= mid) del(lson, l, mid, ql, qr, k);
if (qr > mid) del(rson, mid + 1, r, ql, qr, k);
}
}T1[2];
struct Tr2 {
#define lson (o << 1)
#define rson (o << 1 | 1)
vector<int>nodes[maxn << 4];
void insert(int o, int l, int r, int q, int id) {
if (l <= q && q <= r) nodes[o].push_back(id);
if (l == r) return;
int mid = (l + r) >> 1;
if (q <= mid) insert(lson, l, mid, q, id);
else insert(rson, mid + 1, r, q, id);
}
void del(int o, int l, int r, int ql, int qr, bool k) {
if (ql <= l && r <= qr) {
while (nodes[o].size() && u[nodes[o].back()][k] < ql) {
if (tag[nodes[o].back()][k])
now.push_back(nodes[o].back());
tag[nodes[o].back()][k] = false;
nodes[o].pop_back();
}
return;
}
int mid = (l + r) >> 1;
if (ql <= mid) del(lson, l, mid, ql, qr, k);
if (qr > mid) del(rson, mid + 1, r, ql, qr, k);
}
}T2[2];
bool cmp0(const Pair& a, const Pair& b) {
return v[a.id][0] < v[b.id][0];
}
bool cmp1(const Pair& a, const Pair& b) {
return v[a.id][1] < v[b.id][1];
}
bool cmp2(const Pair& a, const Pair& b) {
return u[a.id][0] > u[b.id][0];
}
bool cmp3(const Pair& a, const Pair& b) {
return u[a.id][1] > u[b.id][1];
}
bool cmp4(const Pair& a, const Pair& b) {
return a.id < b.id;
}
int main() {
FILEIN("two"); FILEOUT("two");
n = read();
for (int i = 2; i <= n; ++i) {
int a = read();
connect(a, i, i - 1, 0);
connect(i, a, i - 1, 0);
edges[0][i - 1] = Pair(i, a, i - 1);
tag[i - 1][0] = true;
}
for (int i = 2; i <= n; ++i) {
int a = read();
connect(a, i, i - 1, 1);
connect(i, a, i - 1, 1);
edges[1][i - 1] = Pair(i, a, i - 1);
tag[i - 1][1] = true;
}
pre(1, 0, 0);
dfn = 0;
pre(1, 0, 1);
for (int i = 1; i <= n - 1; ++i) {
for (int k = 0; k <= 1; ++k) {
if (in[edges[k][i].x][k ^ 1] > in[edges[k][i].y][k ^ 1])
swap(edges[k][i].x, edges[k][i].y);
u[i][k] = in[edges[k][i].x][k ^ 1];
v[i][k] = in[edges[k][i].y][k ^ 1];
}
}
sort(edges[0] + 1, edges[0] + n, cmp0);
sort(edges[1] + 1, edges[1] + n, cmp1);
for (int i = 1; i <= n - 1; ++i) {
T1[0].insert(1, 1, 2 * n, u[edges[0][i].id][0], edges[0][i].id);
T1[1].insert(1, 1, 2 * n, u[edges[1][i].id][1], edges[1][i].id);
}
sort(edges[0] + 1, edges[0] + n, cmp2);
sort(edges[1] + 1, edges[1] + n, cmp3);
for (int i = 1; i <= n - 1; ++i) {
T2[0].insert(1, 1, 2 * n, v[edges[0][i].id][0], edges[0][i].id);
T2[1].insert(1, 1, 2 * n, v[edges[1][i].id][1], edges[1][i].id);
}
sort(edges[0] + 1, edges[0] + n, cmp4);
sort(edges[1] + 1, edges[1] + n, cmp4);
int idx = read();
tag[idx][0] = false;
now.push_back(idx);
puts("Blue");
printf("%d\n", idx);
int k = 1;
while (true) {
swap(cpy, now);
now.clear();
for (auto id : cpy) {
int q = edges[k ^ 1][id].y, p = edges[k ^ 1][id].x;
if (in[q][k ^ 1] < in[p][k ^ 1]) swap(p, q);
T1[k].del(1, 1, 2 * n, in[q][k ^ 1], ou[q][k ^ 1], k);
T2[k].del(1, 1, 2 * n, in[q][k ^ 1], ou[q][k ^ 1], k);
}
if (now.empty()) break;
sort(now.begin(), now.end());
puts(k ? "Red" : "Blue");
for (auto id : now) printf("%d ", id);
puts("");
k ^= 1;
}
return 0;
}