2023/10/11 #D 莫队
类似题目:楼房重建。
受教了。
考虑维护后驱,那么往右延伸的长度就是后缀 min。
那么区间对后缀 min 求和再减去等差数列即可!
考虑后缀的高贵性质再做线段树。
记录 表示对于区间做 这个操作的和。
对于这一类问题可以考虑兔队线段树,大致上是在做 pushup 时这样对左儿子做一遍
那么怎么做呢?
考虑线段树上二分,必然有一个点靠后的 这个限制。一段贡献是区间推平,一段贡献是儿子的值!!
真的好厉害,深深震撼到了。
查询的时候我们考虑对于查询到了的每个 去求 即可。
这个题还要维护一个 set。单点修改即可。
注意到后缀 min 的限制,我们要在 query 时先查询右儿子,然后对于每一个 取 。
感觉现在理解很到位。
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l; i <= r; i ++)
#define per(i, r, l) for (int i = r; i >= l; i --)
#define lc x << 1
#define rc x << 1 | 1
/*王源他不发龙狙证明他没有素质*/
using namespace std;
typedef long long ll;
const int _ = 3e5 + 5;
int n, m;
int a[_], suf[_];
set <int> s[_];
ll ans[_ << 2], mn[_ << 2], res, li;
ll calc (int x, int l, int r, ll lim) {
if (l == r) return min(ans[x], lim);
int mid = (l + r) >> 1;
if (mn[rc] <= lim) return ans[x] - ans[rc] + calc(rc, mid + 1, r, lim);
return calc(lc, l, mid, lim) + 1ll * lim * (r - mid);
}
void pushup (int x, int l, int mid, int r) {
mn[x] = min(mn[lc], mn[rc]);
ans[x] = calc(lc, l, mid, mn[rc]) + ans[rc];
}
void build (int x, int l, int r) {
if (l == r) return ans[x] = mn[x] = suf[l], void();
int mid = (l + r) >> 1;
build(lc, l, mid), build(rc, mid + 1, r);
pushup(x, l, mid, r);
}
void insert (int x, int l, int r, int v, ll k) {
if (l == r) return ans[x] = mn[x] = k, void();
int mid = (l + r) >> 1;
v <= mid ? insert(lc, l, mid, v, k) : insert(rc, mid + 1, r, v, k);
pushup(x, l, mid, r);
}
void query (int x, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
res += calc(x, l, r, li),
li = min(li, mn[x]);
return ;
}
int mid = (l + r) >> 1;
if (qr > mid) query(rc, mid + 1, r, ql, qr);
if (ql <= mid) query(lc, l, mid, ql, qr);
}
int main () {
/*
freopen(".in", "r", stdin);
freopen(".out", "w", stdout);
*/
cin >> n >> m;
rep(i, 1, n) scanf("%d", & a[i]), s[i].insert(n + 1);
per(i, n, 1) suf[i] = *(s[a[i]].begin()), s[a[i]].insert(i);
build(1, 1, n);
while(m --) {
int op, x, y;
scanf("%d%d%d", & op, & x, & y);
if (op == 1) {
auto it = s[a[x]].find(x);
int nxt = *(++ it); --it;
if (it != s[a[x]].begin()) { --it; insert(1, 1, n, *it, nxt); }
s[a[x]].erase(x), it = s[y].lower_bound(x), a[x] = y;
insert(1, 1, n, x, *it);
if (it != s[y].begin()) --it, insert(1, 1, n, *it, x);
s[y].insert(x);
} else {
res = 0, li = y + 1;
query(1, 1, n, x, y);
res -= 1ll * (y + x) * (y - x + 1) / 2;
printf("%lld\n", res);
}
}
return 0;
}
/*
4 3
1 1 2 1
2 1 3
1 2 3
2 1 4
*/
登高自卑,行远自迩。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现