求助关于线段树分治的问题
查看原帖
求助关于线段树分治的问题
759326
DAMDAM楼主2024/9/3 18:42

rt

首先,并查集只能撤销刚才做的操作,那么我们撤销操作一定是按时间倒序撤销之前加入的操作。

如果上面这句话是对的,那么这份代码应该可以被 hack。

#include <cstdio>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
int n, m, k, fa[maxn << 1], siz[maxn << 1];
int find(const int &x) { return x == fa[x] ? x : find(fa[x]); }
bool check[maxn << 2];
struct Edge { int from, to; };
vector<Edge> val[maxn << 2];
void Modify(const int &l, const int &r, const Edge &e, const int &s = 1, const int &t = k, const int &p = 1) {
    if (r < s || t < l) return;
    if (l <= s && t <= r) return void(val[p].emplace_back(e));
    int mid = s + ((t - s) >> 1);
    if (l <= mid) Modify(l, r, e, s, mid, p << 1);
    if (r > mid) Modify(l, r, e, mid + 1, t, p << 1 | 1);
}
void Undo(const vector<Edge> &v) { for (auto it : v) siz[it.from] -= siz[it.to], fa[it.to] = it.to; } //here's the problem
void Head_s(const int &s = 1, const int &t = k, const int &p = 1) {
    vector<Edge> upd;
    if (check[p]) {
        int u, v, x, y;
        for (auto it : val[p]) {
            x = n + (u = it.from), y = n + (v = it.to), u = find(u), v = find(v), x = find(x), y = find(y);
            if (u == v && (check[p] = 0, 1)) break;
            if (siz[u] < siz[y]) swap(u, y);
            if (siz[v] < siz[x]) swap(v, x);
            upd.emplace_back(Edge{u, y}), upd.emplace_back(Edge{v, x});
            siz[u] += siz[y], fa[y] = u, siz[v] += siz[x], fa[x] = v;
        }
    }
    if (s == t) return printf("%s", check[p] ? "Yes" : "No"), putchar(10), Undo(upd);
    check[p << 1] = check[p << 1 | 1] = check[p];
    int mid = s + ((t - s) >> 1);
    Head_s(s, mid, p << 1), Head_s(mid + 1, t, p << 1 | 1), Undo(upd);
}

int main() {
    scanf("%d%d%d", &n, &m, &k), check[1] = 1;
    for (int i = 1; i <= (n << 1); ++i) fa[i] = i, siz[i] = 1;
    for (int x, y, l, r; m; --m) scanf("%d%d%d%d", &x, &y, &l, &r), Modify(l + 1, r, {x, y});
    Head_s();
    return 0;
}

但是事实是,这个代码成功 AC。

那么我想请问各个巨佬们,我的推断正不正确?

2024/9/3 18:42
加载中...