CF351D Jeff and Removing Periods

CF351D Jeff and Removing Periods
HH的项链 加强版本。
容易发现,这肯定和一段区间内数的种类数有关,然后,因为第一次操作的时候不能重排数列,那么我们只用讨论第一次的情况:

  • 可以一次把这种数删完。
  • 不能一次把这种数删完。
    那么我们可以记录一个 (fa_{i}) 代表 (i) 前面只要跨过区间 ([fa_i, i]) 就不能一次把这种数删完的第一个点。
    可以发现有两种转移

[fa_{i} = pre_{pre_{i}} [i - pre_{i} e pre_{i} - pre_{pre_{i}}] ]

[fa_{i} = fa_{pre_{i}} [i - pre_{i} = pre_{i} - pre_{pre_{i}}] ]

然后整俩树状数组一整就完了。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

typedef long long ll;
const ll MAXN = 1e6+10;

ll N, M, val[MAXN], nxt[MAXN], lst[MAXN], pre[MAXN], fa[MAXN], ans[MAXN];

struct que {
    ll l, r, id;
    friend bool operator < (que a, que b) {return a.r < b.r;}
} Q[MAXN];

struct arr {
    ll C[MAXN];

    void add(ll x, ll v) {
    	if (!x) return;
        while (x <= N) {
            C[x] += v;
            x += (x & (-x));
        }
    }
    
    ll ask(ll x) {
        ll ret = 0;
        while (x) {
            ret += C[x];
            x -= (x & (-x));
        }
        return ret;
    }
} t1, t2;

int main() {
    scanf("%lld", &N);
    for (ll i = 1; i <= N; i++) {
        scanf("%lld", val+i);
        nxt[lst[val[i]]] = i;
        pre[i] = lst[val[i]];
        lst[val[i]] = i;
        if (i - pre[i] == pre[i] - pre[pre[i]]) fa[i] = fa[pre[i]];
        else fa[i] = pre[pre[i]];
    }
    scanf("%lld", &M);
    for (ll i = 1; i <= M; i++) 
        scanf("%lld%lld", &Q[i].l, &Q[i].r), Q[i].id = i;
    sort(Q+1, Q+M+1);
    ll now = 0;
    for (ll i = 1; i <= M; i++) {
        while (now < Q[i].r) {
            ++now;
            t1.add(now, 1);
            t1.add(pre[now], -1);
            t2.add(fa[now], 1);
            t2.add(fa[pre[now]], -1);
        }
        ll tem1 = t1.ask(Q[i].r) - t1.ask(Q[i].l - 1), tem2 = t2.ask(Q[i].r) - t2.ask(Q[i].l - 1);
        ans[Q[i].id] = tem1 + (tem1 == tem2);
    }
    for (ll i = 1; i <= M; i++) 
        printf("%lld
", ans[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/Gensokyo-Alice/p/13792709.html