mex数组

给定数列 a,对于每个 i 询问多少个区间的 mex 等于 i

考虑转化成求多少个 mexi 的区间,设为 ansi,容易发现,设右端点为 r, pi=max{jr|aj=i},则 mex 不小于于 i 的合法左端点数量为 min{pj|j<i}

每次暴力维护 pi,你就有了 50 分的做法。。

再考虑神秘做法,显然 ans0=n(n+1)2,我们从 0 n 枚举一个数 i,只考虑 ansi,容易发现实际上比 i 大的数怎么出现对 ansi 都没有影响,我们要维护的是 p0 i 的前缀最小值。ansi 实际上就是我们之前右端点枚举到每个位置时的前缀最小值之和。

考虑 0 i1 的贡献我们都已经算过,我们枚举序列里每一个为 i 的位置,它对序列 pi 的影响 本质上还是一个前缀取 min,可以吉司机线段树维护。

#include <bits/stdc++.h>

using namespace std;

const int N = 2e6 + 5;

int mx[N << 2], mn[N << 2], lazy[N << 2];
long long sum[N << 2];

inline void add(int now, int x, int l, int r) {
   mx[now] = mn[now] = lazy[now] = x;
   sum[now] = 1ll * (r - l + 1) * x;
}

inline void update(int now) {
   mn[now] = mn[now << 1]; mx[now] = mx[now << 1 | 1];
   sum[now] = sum[now << 1] + sum[now << 1 | 1];
}

inline void pushdown(int now, int l, int r) {
   if (lazy[now] == -1) return ;
   add(now << 1, lazy[now], l, l + 1 >> 1);
   add(now << 1 | 1, lazy[now], (l + r >> 1) + 1, r);
   lazy[now] = -1;
}

inline void build(int now, int l, int r) {
   lazy[now] = -1;
   if (l >= r) {
   	add(now, l, l, r); lazy[now] = -1;
   	return ;
   } build(now << 1, l, l + r >> 1);
   build(now << 1 | 1, (l + r >> 1) + 1, r);
   update(now);
}

inline void modify(int now, int l, int r, int q, int x) {
   if (q < l || mx[now] <= x) return ;
   if (r <= q && mn[now] >= x) {
   	add(now, x, l, r);
   	return ;
   } pushdown(now, l, r);
   int mid = l + r >> 1;
   modify(now << 1, l, mid, q, x);
   if (q > mid) modify(now << 1 | 1, mid + 1, r, q, x);
   update(now);
}

inline void otp(long long x) {
   (x >= 10) ?otp(x / 10), putchar((x % 10) ^ 48) : putchar(x ^ 48);
}

inline int read() {
   register int s = 0; register char ch = getchar();
   while (!isdigit(ch)) ch = getchar();
   while (isdigit(ch)) s = (s << 1) + (s << 3) + (ch & 15), ch = getchar();
   return s;
}

int a[N], lst[N], pre[N];
long long ans[N];

int main() {
   int n = read();
   for (int i = 1; i <= n; ++i) {
   	a[i] = read();
   	pre[i] = lst[a[i]]; lst[a[i]] = i;
   }
   ans[0] = 1ll * n * (n + 1) / 2;
   build(1, 1, n);
   for (int i = 0; i <= n; ++i) {
   	int l = n;
   	for (int j = lst[i]; j; l = j - 1, j = pre[j]) {
   		modify(1, 1, n, l, j);
   	}
   	modify(1, 1, n, l, 0);
   	ans[i + 1] += sum[1];
   	otp(ans[i] - ans[i + 1]); putchar(' ');
   } return 0;
}
posted @   Smallbasic  阅读(227)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示