Loading

CF2115F2 Gellyfish and Lycoris Radiata 做题记录

果然我的数据结构还是太弱了。 link

对于 F1,可以操作分块。


这里谈一谈对操作分块的理解:

每次询问时,对块内的修改需要快速查询,或者与块前面的修改快速结合。

对于前面的操作,有两种处理方法:

  • 将前面的修改打包,也就是每求完一个块就加入对应的修改到全局维护中,然后用不超过根号左右的复杂度查询。

  • 依次扫描前面每个块,快速地计算贡献。

而操作分块地精髓在于前面的修改可以看作常量,只需要考虑新增的那部分修改。这很好地体现了分块的局部打包的思想。


操作分块后,当前块内的修改很容易处理,并维护在若干次修改之前的位置是什么。

对于前面的修改,可以从后往前扫描每个块。不难发现 \(k\) 次修改会将整个序列分成不超过 \(\mathcal O(k)\) 个连续段,每个块预处理出每个连续段的集合,以及位置的变换。

如果集合中最小值被删过就直接 erase,删数的复杂度和数的个数相关所以是对的,时间复杂度为 \(\mathcal O(q\sqrt q)\)

对于 F2,考虑直接上线段树(二进制分组)。不过如果仅仅是二进制分组,不能很好地维护信息,而线段树显然更强。

线段树和分块的一个很大的区别在于:信息需要支持合并。

对于两组大小为 \(a\)\(b\) 的修改,我么可以以 \(\mathcal O(a + b)\) 的复杂度合并,所以是对的。

唯一的问题在于,我们很难支持集合的维护,因为集合的对位合并时间复杂度是很劣的。

但这是线段树啊,是可以线段树二分的!也就是说,我们只需要维护每个连续段的集合是否为空就行了。

每个非叶子处的连续段一定都是由两个连续段取交合并得到,可以记作左右两个儿子。每次删掉一个数的时候,相当于将一个叶子处的连续段集合删空,然后我们枚举该点的父亲递归 update 即可,这部分总复杂度和所有点处的连续段总数有关,所以是对的。

总时间复杂度为 \(\mathcal O(q\log ^ 2q)\)


维护时间维真神了好吧。


点击查看代码
#include <bits/stdc++.h>
#define ll int
#define LL long long
#define ull unsigned
#define uLL unsigned LL
#define fi first
#define se second
#define mkp make_pair
#define pir pair<ll, ll>
#define pb push_back
#define i128 __int128
using namespace std;
template <class T>
const inline void rd(T &x) {
    char ch;
    bool neg = 0;
    while (!isdigit(ch = getchar()))
        if (ch == '-')
            neg = 1;
    x = ch - '0';
    while (isdigit(ch = getchar())) x = (x << 1) + (x << 3) + ch - '0';
    if (neg)
        x = -x;
}
const ll maxn = 3e5 + 10, M = 12e6 + 10, inf = 1e9, mod = 1e9 + 7, iv = mod - mod / 2;
const LL INF = 1e18 + 5;
ll power(ll a, ll b = mod - 2, ll p = mod) {
    ll s = 1;
    while (b) {
        if (b & 1)
            s = 1ll * s * a % p;
        a = 1ll * a * a % p, b >>= 1;
    }
    return s;
}
template <class T, class _T>
const inline ll pls(const T x, const _T y) { return x + y >= mod ? x + y - mod : x + y; }
template <class T, class _T>
const inline ll mus(const T x, const _T y) { return x < y ? x + mod - y : x - y; }
template <class T, class _T>
const inline void add(T &x, const _T y) { x = x + y >= mod ? x + y - mod : x + y; }
template <class T, class _T>
const inline void sub(T &x, const _T y) { x = x < y ? x + mod - y : x - y; }
template <class T, class _T>
const inline void chkmax(T &x, const _T y) { x = x < y ? y : x; }
template <class T, class _T>
const inline void chkmin(T &x, const _T y) { x = x < y ? x : y; }

ll n, q, m, lstans, lc[M], rc[M];

struct info { ll len, p, q, t, c; } a[M];
vector <ll> fa[M];

set <ll> st[maxn];

void update(ll u) {
    for(ll f: fa[u])
        if(!a[lc[f]].c && !a[rc[f]].c) {
            a[f].c = 0;
            update(f);
        }
}
ll ask(ll u) {
    if(lc[u] < 0) return -lc[u];
    if(a[lc[u]].c) return ask(lc[u]);
    return ask(rc[u]);
}

struct SGT {
    vector <ll> P[maxn << 2], Q[maxn << 2];
    void pushup(ll p) {
        ll i = 0, j = 0, x = p << 1, y = p << 1|1;
        while(i < Q[x].size() && j < P[y].size()) {
            ll u = Q[x][i], v = P[y][j];
            ll l = max(a[u].q, a[v].p), r = min(a[u].q
             + a[u].len - 1, a[v].p + a[v].len - 1);
            if(l <= r) {
                a[++m].len = r - l + 1, a[m].t = a[u].t ^ a[v].t;
                a[m].p = a[u].p, a[m].q = a[v].q;
                fa[u].pb(m), fa[v].pb(m);
                lc[m] = u, rc[m] = v;
                a[m].c = a[u].c | a[v].c;
                if(a[u].t == 0) a[m].p += l - a[u].q;
                else a[m].p += a[u].q + a[u].len - 1 - r;
                if(a[v].t == 0) a[m].q += l - a[v].p;
                else a[m].q += a[v].p + a[v].len - 1 - r;
            }
            if(i + 1 < Q[x].size() && (j + 1 == P[y].size()
             || a[Q[x][i + 1]].q <= a[P[y][j + 1]].p)) ++i;
            else ++j;
        }
        for(ll i = 0; i < P[x].size(); i++) {
            ll u = P[x][i];
            if(a[u].t) reverse(fa[u].begin(), fa[u].end());
            for(ll f: fa[u]) P[p].pb(f);
        }
        for(ll i = 0; i < Q[y].size(); i++) {
            ll u = Q[y][i];
            if(a[u].t) reverse(fa[u].begin(), fa[u].end());
            for(ll f: fa[u]) Q[p].pb(f);
        }
    }
    void upd(ll p, ll l, ll r, ll x, ll typ, ll k) {
        if(l == r) {
            if(typ == 2) { a[++m] = (info) {n, 1, 1, 0, 0}; P[p].pb(m), Q[p].pb(m); return; }
            a[++m] = (info) {k, 1, 1, typ, typ ^ 1};
            P[p].pb(m), Q[p].pb(m);
            lc[m] = rc[m] = -x;
            if(k < n) {
                a[++m] = (info) {n - k, k + 1, k + 1, 0, 0};
                P[p].pb(m), Q[p].pb(m);
            }
            return;
        } ll mid = l + r >> 1;
        if(x <= mid) upd(p << 1, l, mid, x, typ, k);
        else upd(p << 1|1, mid + 1, r, x, typ, k);
        if(x == r) pushup(p);
    }
    void modify(ll p, ll l, ll r, ll x) {
        if(l == r) {
            a[P[p][0]].c = 0;
            update(P[p][0]);
            return;
        } ll mid = l + r >> 1;
        if(x <= mid) modify(p << 1, l, mid, x);
        else modify(p << 1|1, mid + 1, r, x);
    }
    ll sr[55], len;
    ll Get(ll p, ll l, ll r, ll x, ll k) {
        if(r <= x) {
            a[0].q = k;
            ll e = upper_bound(Q[p].begin(), Q[p].end(), 0, [](ll i, ll j) {
                return a[i].q < a[j].q;
            }) - Q[p].begin() - 1;
            ll u = Q[p][e];
            k += a[u].p - a[u].q;
            if(a[u].t) k = 2 * a[u].p + a[u].len - 1 - k;
            sr[++len] = u; return k;
        } ll mid = l + r >> 1;
        if(x > mid) k = Get(p << 1|1, mid + 1, r, x, k);
        return Get(p << 1, l, mid, x, k);
    } 
    ll solve(ll t, ll k) {
        len = 0, Get(1, 1, q, t, k);
        reverse(sr + 1, sr + 1 + len);
        for(ll i = 1; i <= len; i++) {
            if(a[sr[i]].c) return ask(sr[i]);
        } return 0;
    }
} tr;

bool ffs[maxn];

int main() {
    rd(n), rd(q);
    for(ll _ = 1; _ <= q; _++) {
        ll op, x, y; rd(op), rd(x), rd(y);
        x = (x + lstans - 1) % (op == 3? q : n) + 1;
        y = (y + lstans - 1) % n + 1;
        tr.upd(1, 1, q, _, op - 1, x);
        if(op == 3 && ffs[x]) tr.modify(1, 1, q, x), ffs[x] = false;
        if(op == 1) ffs[_] = true;
        printf("%d\n", lstans = tr.solve(_, y));
    }
	return 0;
}
posted @ 2025-12-17 15:16  Sktn0089  阅读(7)  评论(0)    收藏  举报