1 条题解

  • 0
    @ 2025-8-24 23:10:35

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar yuanruiqi
    我该在哪里停留?我问我自己。

    搬运于2025-08-24 23:10:35,当前版本为作者最后更新于2025-03-02 19:21:07,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    下面我将给出一个 O((m+q)nω+qn)O(\frac{(m+q)n}{\omega}+q\sqrt{n}) 的做法,考场大样例用时不到 2s。

    将可达关系和询问区间都视作限制,我们首先尝试得到集合 {ixi}\set{i\mid x\to i}{iai[l,r]}\set{i\mid a_i\in[l,r]} 的交,前者容易通过拓扑排序在 O(nmω)O(\frac{nm}{\omega}) 的复杂度下预处理。对后者使用根号分块维护。

    {iai[l,r]}\set{i\mid a_i\in[l,r]} 视作 $\set{i\mid a_i\ge l}\setminus \set{i\mid a_i\ge r+1}$,即用两个后缀的异或表示。令块长 s=ns=\sqrt{n},分块维护根号个 bitset Ax={iaixs}A_x=\set{i\mid a_i\ge xs}。于是单次修改是 O(n)O(\sqrt{n}) 的。单次查询后缀 ii 可以取出 AxA_x 其中 x=isx=\lceil\frac{i}{s}\rceil,并暴力加入满足 bj[i,xs)b_j\in[i,xs)jj,复杂度为 O(nω+n)O(\frac{n}{\omega}+\sqrt{n})

    令得到的限制集合为 CC,求 maxiCbi\max_{i\in C}b_i。我们对 bb 维护相同的分块 Bx={ibixs}B_x=\set{i\mid b_i\ge xs},下面只需要找到 maxCBx0x\max_{|C\cap B_x|\neq 0} x 即最靠后的和 CC 有交的块,再块内枚举即可。

    这里我的实现需要用到手写 bitset,并记 C(x)C(x)CC 中的第 xx 个 ull 表示的集合,同理有 Bi(x)B_i(x)。对于 ii00nω\lceil\frac{n}{\omega}\rceil 枚举 C(i)C(i),并在过程中维护指针 pp,表示 C[0,is)C\cap [0,is)BB 有交的最靠后的块的编号。若 C(i)C(i)Bp(i)B_p(i) 无交则跳过,否则检查 C(i)C(i)Bp+1(i)B_{p+1}(i) 是否有交,尝试更新 p:=p+1p:=p+1 并继续检查,不难发现最终得到的 pp 即为所求。由于 ull 的单次求交是 O(1)O(1) 的,共有 O(nω+n)O(\frac{n}{\omega}+\sqrt{n}) 次检查交集,所以这部分复杂度同样是 O(nω+n)O(\frac{n}{\omega}+\sqrt{n})

    下面是考场代码,没有细节,实现并不复杂。

    #include <bits/stdc++.h>
    using namespace std;
    using i64 = long long;
    using u64 = unsigned long long;
    constexpr int maxn = 100000 + 10;
    constexpr int len = 340;
    constexpr int siz = 1570;
    struct bitst
    {
        u64 a[siz];
        void reset()
        {
            memset(a, 0, sizeof(a));
        }
        void set(int x)
        {
            a[(x >> 6)] |= 1ull << (x & 63);
        }
        void flip(int x)
        {
            a[(x >> 6)] ^= 1ull << (x & 63);
        }
        void operator|=(const bitst &b)
        {
            for (int i=0;i<siz;++i) a[i] |= b.a[i];
        }
        void operator^=(const bitst &b)
        {
            for (int i=0;i<siz;++i) a[i] ^= b.a[i];
        }
        void operator&=(const bitst &b)
        {
            for (int i=0;i<siz;++i) a[i] &= b.a[i];
        }
        int val(int x)
        {
            return a[x >> 6] >> (x & 63) & 1;
        }
    };
    bitst G[maxn];
    bitst A[len], B[len];
    vector<int> e[maxn];
    #define lt(x) (!(x) ? 1 : (x) * len)
    #define rt(x) (min(((x) * len + len - 1), n))
    int a[maxn], b[maxn];
    int ia[maxn], ib[maxn];
    int n, m, q;
    int idx;
    void solve()
    {
        cin >> n >> m >> q;
        for (int i=1;i<=n;++i) e[i].clear();
        for (int i=1;i<=m;++i)
        {
            int u, v;
            cin >> u >> v;
            e[u].emplace_back(v);
        }
        for (int i=n;i>=1;--i)
        {
            G[i].reset();
            G[i].set(i);
            for (int v : e[i]) G[i] |= G[v];
        }
        int k = 0;
        while (lt(k) <= n) ++k;
        for (int i=0;i<=k;++i) A[i].reset(), B[i].reset();
        for (int i=1;i<=n;++i) cin >> a[i], ia[a[i]] = i;
        for (int i=1;i<=n;++i) cin >> b[i], ib[b[i]] = i;
        for (int i=1;i<=n;++i) A[a[i] / len].set(i), B[b[i] / len].set(i);
        for (int i=k-2;i>=0;--i) A[i] |= A[i + 1], B[i] |= B[i + 1];
        while (q--)
        {
            int o;
            cin >> o;
            if (o == 1)
            {
                int x, y;
                cin >> x >> y;
                int l = a[x] / len, r = a[y] / len;
                if (l > r) swap(l, r);
                for (int i=l+1;i<=r;++i) A[i].flip(x), A[i].flip(y);
                swap(a[x], a[y]);
                swap(ia[a[x]], ia[a[y]]);
            }
            else if (o == 2)
            {
                int x, y;
                cin >> x >> y;
                int l = b[x] / len, r = b[y] / len;
                if (l > r) swap(l, r);
                for (int i=l+1;i<=r;++i) B[i].flip(x), B[i].flip(y);
                swap(b[x], b[y]);
                swap(ib[b[x]], ib[b[y]]);
            }
            else
            {
                int x, l, r;
                cin >> x >> l >> r; ++r;
                int y = (r + len - 1) / len;
                bitst u = A[y];
                y = min(n + 1, len * y);
                for (int i=r;i<y;++i) u.set(ia[i]);
                y = (l + len - 1) / len;
                u ^= A[y];
                y = min(n + 1, len * y);
                for (int i=l;i<y;++i) u.flip(ia[i]);
                u &= G[x];
                int p = 0;
                for (int i=0;i<siz&&p<k-1;++i)
                {
                    while (u.a[i] & B[p + 1].a[i]) ++p;
                }
                l = lt(p); r = rt(p);
                int ans = 0;
                for (int i=r;i>=l;--i) if (u.val(ib[i]))
                {
                    ans = i;
                    break;
                }
                cout << ans << '\n';
            }
        }
    }
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        int c, t;
        cin >> c >> t;
        while (t--) solve();
        return 0;
    }
    
    
    • 1

    信息

    ID
    11615
    时间
    9000ms
    内存
    2048MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者