Loading

【题解】CF848C Goodbye Souvenir

如果命运对你缄默,你就活给他看。

思路

cdq 分治。

有各种懂哥写了科技做法,比如树套树和二维分块,有点离谱。

首先考虑答案的形式。

\(lst_i\)\([1, i)\)\(a_i\) 最后一次出现的位置,则对于 \([l, r]\) 的询问,答案为 \(\sum\limits_{i = l}^r i - lst_i [lst_i \geq l]\)

发现其实是对满足下面条件的 \(i - lst_i\) 求和:

  1. \(l \leq i \leq r\)

  2. \(lst_i \geq l\)

  3. 满足操作的时间轴

把初始数组抽象成 \(n\) 次修改,那么就是一个三维偏序。

直接上 cdq 分治离线下来,动态转静态做就行。

时间复杂度 \(O(n \log^2 n)\)

代码

#include <cstdio>
#include <set>
#include <algorithm>
using namespace std;

typedef long long ll;

const int maxn = 1e5 + 5;
const int maxm = 1e5 + 5;
const int opt_sz = maxn * 10;

struct opt
{
    int tp, pos, lst, nega;

    int val() { return nega * (pos - lst); }
} qry[opt_sz], tmp[opt_sz];

int n, m, len;
int a[maxn], tp[maxm];
ll ans[maxm];
set<int> pos[maxn];

namespace BIT
{
    ll c[maxn];

    int lowbit(int x) { return x & (-x); }

    void update(int p, int w) { for (int i = p; i <= n; i += lowbit(i)) c[i] += w; }

    ll query(int p)
    {
        ll res = 0;
        for (int i = p; i; i -= lowbit(i)) res += c[i];
        return res;
    }
}

void modify(int l, int tp)
{
    int lft = -1, rgt = -1;
    auto it = pos[a[l]].lower_bound(l);
    if (it != pos[a[l]].begin())
    {
        it--, lft = (*it);
        qry[++len] = (opt){1, l, lft, tp ? 1 : -1};
    }
    it = pos[a[l]].upper_bound(l);
    if (it != pos[a[l]].end())
    {
        rgt = (*it);
        qry[++len] = (opt){1, rgt, l, tp ? 1 : -1};
    }
    if ((~lft) && (~rgt)) qry[++len] = (opt){1, rgt, lft, tp ? -1 : 1};
    if (tp) pos[a[l]].insert(l);
    else pos[a[l]].erase(l);
}

void solve(int l, int r)
{
    if (l == r) return;
    int mid = (l + r) >> 1, i, j, k;
    solve(l, mid);
    solve(mid + 1, r);
    for (i = mid + 1, j = l; i <= r; i++)
    {
        if (qry[i].tp == 1) continue;
        while ((j <= mid) && (qry[j].pos <= qry[i].pos)) { if (qry[j].tp == 1) BIT::update(qry[j].lst, qry[j].val()); j++; }
        ans[qry[i].nega] += BIT::query(n) - BIT::query(qry[i].lst - 1);
    }
    for (i = l; i < j; i++)
        if (qry[i].tp == 1) BIT::update(qry[i].lst, -qry[i].val());
    for (i = l, j = mid + 1, k = l; k <= r; k++)
        if ((j > r) || ((qry[i].pos <= qry[j].pos) && (i <= mid))) tmp[k] = qry[i++];
        else tmp[k] = qry[j++];
    for (i = l; i <= r; i++) qry[i] = tmp[i];
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        pos[a[i]].insert(i);
        if (pos[a[i]].size() > 1) qry[++len] = (opt){1, i, *(--pos[a[i]].rbegin()), 1};
    }
    int qcnt = 0;
    while (m--)
    {
        int tp, l, r, v;
        scanf("%d", &tp);
        if (tp == 1)
        {
            scanf("%d%d", &l, &v);
            modify(l, 0);
            a[l] = v;
            modify(l, 1);
        }
        else
        {
            scanf("%d%d", &l, &r);
            qry[++len] = (opt){2, r, l, ++qcnt};
        }
    }
    // printf("debug %d\n", qcnt);
    solve(1, len);
    for (int i = 1; i <= qcnt; i++) printf("%lld\n", ans[i]);
    return 0;
}
posted @ 2023-01-14 11:04  kymru  阅读(42)  评论(0编辑  收藏  举报