C. Goodbye Souvenir(CDQ 或 树套树)
C. Goodbye Souvenir
∑i=LRi?preAi[preAi≥L]\sum\limits_{i = L} ^{R} i - pre_{A_i} [pre_{A_i} \geq L]i=L∑R?i?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; }總結
以上是生活随笔為你收集整理的C. Goodbye Souvenir(CDQ 或 树套树)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU 6428 Problem C.
- 下一篇: Python数据分析工具Pandas——