two 题解

一、题目:

two 题解
two 题解
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\)。

  1. \(T_1\) 以每条边的 \(u\) 作为下标,节点 \((L,R)\)上存储 \(L\leq u\leq R\) 的那些边,并按 \(v\) 从小到大的顺序存储。
  2. \(T_2\) 以每条边的 \(v\) 作为下标,节点 \((L,R)\) 上存储 \(L\leq v\leq R\)的那些边,并按 \(u\) 从大到小的顺序存储。

对于一条已经在上一轮被删除的边 \((p,q)\),如何查询有多少边对它有害呢?

  1. 在 \(T_1\) 中所有满足 \(in[q]\leq L\leq R\leq ou[q]\) 的节点上,删除所有 \(v>ou[q]\) 的边。
  2. 在 \(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;
}
上一篇:Probabilistic two-stage detection


下一篇:STR from Two-Dimensional Perspective AAAI2019