C. Goodbye Souvenir
∑i=LRi−preAi[preAi≥L]\sum\limits_{i = L} ^{R} i - pre_{A_i} [pre_{A_i} \geq L]i=L∑Ri−preAi[preAi≥L],进一步考虑即∑i−preAi[i≤R,preAi≥L]\sum i - pre_{A_i}[i \leq R, pre_{A_i} \geq L]∑i−preAi[i≤R,preAi≥L],
① i≤Ri \leq Ri≤R,
② preAi≥Lpre_{A_i} \geq LpreAi≥L
③ 时间ttt维度
由此这个问题被转化为了一个标准的三维偏序问题,第一维为时间ttt,第二维为iii,第三维为preAipre_{A_i}preAi,在第三维中动态插入i−preAii - pre_{A_i}i−preAi的值。
因此考虑如下一个结构体:
struct {int op, x, y, f, id;
};
依次为:存放操作种类,存放iii,存放preAipre_{A_i}preAi,存放i−preAii - pre_{A_i}i−preAi,存放对第几个询问贡献答案。
考虑修改操作,对应pre[p],p,next[p]pre[p], p, next[p]pre[p],p,next[p],我们修改的是ppp节点的信息,也就是这个节点不复存在了,
所以显然加入操作{1,p,pre[p],pre[p]−p,0}\{1, p, pre[p], pre[p] - p, 0\}{1,p,pre[p],pre[p]−p,0},也就是减去之前存在的{1,p,pre[p],p−pre[p],0}\{1, p, pre[p], p - pre[p], 0\}{1,p,pre[p],p−pre[p],0},
考虑其对后继的影响,显然也要减去之前存在的后继信息,也就是加入{1,next[p],p,p−next[p],0}\{1, next[p], p, p - next[p], 0\}{1,next[p],p,p−next[p],0},
然后加上修改后其后继的值{1,next[p],pre[p],next[p]−pre[p],0}\{1, next[p], pre[p], next[p] - pre[p], 0\}{1,next[p],pre[p],next[p]−pre[p],0}。
同样的对于修改后,也就是插入了一个新的值,我们也要先删去当前加入的点的后继,然后再加入当前点,以及后继的最新信息。
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N = 1e5 + 10;int a[N], pre[N], n, m, top;ll ans[N], tree[N];set<int> st[N];struct Res {int op, x, y, f, id;
}Q[7 * N];bool cmpx(Res a, Res b) {return a.x < b.x;
}bool cmpid(Res a, Res b) {return a.id < b.id;
}inline int lowbit(int x) {return x & (-x);
}void clear(int x) {while (x) {tree[x] = 0;x -= lowbit(x);}
}void update(int x, int v) {while (x) {tree[x] += v;x -= lowbit(x);}
}ll query(int x) {ll res = 0;while (x <= n) {res += tree[x];x += lowbit(x);}return res;
}void CDQ(int l, int r) {if (l == r) {return ;}int mid = l + r >> 1;CDQ(l, mid), CDQ(mid + 1, r);for (int i = l, j = mid + 1; j <= r; j++) {while (i <= mid && Q[i].x <= Q[j].x) {if (Q[i].op & 1) {update(Q[i].y, Q[i].f);}i++;}if (Q[j].op == 2) {ans[Q[j].id] += query(Q[j].y);}}for (int i = l; i <= mid; i++) {clear(Q[i].y);}sort(Q + l, Q + r + 1, cmpx);
}int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);scanf("%d %d", &n, &m);for (int i = 1; i <= n; i++) {st[i].insert(0);}for (int i = 1; i <= n; i++) {scanf("%d", &a[i]);pre[i] = *--st[a[i]].end();st[a[i]].insert(i);Q[++top] = {1, i, pre[i], i - pre[i], 0};}for (int i = 1, op, x, y; i <= m; i++) {scanf("%d %d %d", &op, &x, &y);if (op & 1) {auto it = st[a[x]].lower_bound(x);Q[++top] = {1, x, pre[x], pre[x] - x, 0};it++;if (it != st[a[x]].end()) {Q[++top] = {1, *it, pre[*it], pre[*it] - *it, 0};pre[*it] = pre[x];Q[++top] = {1, *it, pre[*it], *it - pre[*it], 0};}st[a[x]].erase(x);a[x] = y;st[a[x]].insert(x);it = st[a[x]].lower_bound(x);it--;pre[x] = *it;Q[++top] = {1, x, pre[x], x - pre[x], 0};++it, ++it;if (it != st[a[x]].end()) {Q[++top] = {1, *it, pre[*it], pre[*it] - *it, 0};pre[*it] = x;Q[++top] = {1, *it, pre[*it], *it - pre[*it], 0};}}else {Q[++top] = {op, y, x, 0, i};}}CDQ(1, top);sort(Q + 1, Q + 1 + top, cmpid);for (int i = 1; i <= top; i++) {if (Q[i].op == 2) {printf("%lld\n", ans[Q[i].id]);}}return 0;
}