【题解】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\) 求和:
-
\(l \leq i \leq r\)
-
\(lst_i \geq l\)
-
满足操作的时间轴
把初始数组抽象成 \(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;
}