AT_jsc2019_final_h Distinct Integers 题解 线段树单侧递归
题目链接:https://www.luogu.com.cn/problem/AT_jsc2019_final_h
解题思路:完全来自 ikusiad大佬的博客
额外提一嘴:
如果我们用 \(p_i\) 表示 \(a_i\) 前面和 \(a_i\) 最接近的那个等于 \(a_i\) 的元素的下标(如果 \(a_i\) 前面没有等于 \(a_i\) 的数,则令 \(pre_i = -1\))。
则,我们可以定义一个 \(p_i = \max\limits_{0 \le j \le i} pre_j\) 。
则对于每次询问的区间 \([l, r)\),答案为
\[\sum_{i = l}^{r-1} i - p_i
\]
示例程序:
还在debug,还没AC,AC了再贴……
2026/4/21 更新:线段树没写出来,and 暂时不想写了,于是拿分块过了这道题,时间复杂度 \(O(m \sqrt{n} \log n)\)。
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 5, maxb = sqrt(maxn) + 5;
int n, blo, Q, a[maxn], pre[maxn], PRE[maxn];
set<int> st[maxn];
long long sum[maxb], ss[maxn];
int id(int x) {
return (x - 1) / blo + 1;
}
// 更新第 p 个分块
void update(int p) {
int l = (p - 1) * blo + 1, r = min(p * blo, n);
sum[p] = PRE[l] = ss[l] = pre[l];
for (int i = l+1; i <= r; i++) {
PRE[i] = max(PRE[i-1], pre[i]);
sum[p] += PRE[i];
ss[i] = ss[i-1] + PRE[i];
}
}
// 将 pre[x] 修改为 y
void update(int x, int y) {
// printf("update pre[%d] = %d\n", x, y);
pre[x] = y;
update(id(x));
}
long long query(int l, int r) {
long long ans = 0;
int x = l-1;
if (id(l) + 1 >= id(r)) {
for (int i = l; i <= r; i++) {
x = max(x, pre[i]);
// printf("[*] + %d\n", x);
ans += x;
}
return ans;
}
for (int i = l; i <= id(l)*blo; i++) {
x = max(x, pre[i]);
// printf("[1] + %d\n", x);
ans += x;
}
for (int i = id(l)+1; i < id(r); i++) {
if (x >= PRE[i*blo]) {
ans += 1ll * x * blo;
// printf("[2.1] + %d * %d\n", x, blo);
}
else {
int p = upper_bound(PRE+(i-1)*blo+1, PRE+i*blo+1, x) - PRE;
assert(p >= (i-1)*blo+1);
int len = p - ((i-1)*blo+1);
// printf("[2.2] + %d * %d + %lld - %lld \n", x, len, ss[i*blo], ss[p-1]);
if (len > 0)
ans += 1ll * x * len + ss[i*blo] - ss[p-1];
else
ans += ss[i*blo] - ss[p] + PRE[p];
x = PRE[i*blo];
}
}
for (int i = (id(r)-1)*blo+1; i <= r; i++) {
x = max(x, pre[i]);
// printf("[3] + %d\n", x);
ans += x;
}
return ans;
}
int main() {
scanf("%d%d", &n, &Q);
blo = sqrt(n);
for (int i = 0; i < n; i++) {
st[i].insert(0);
}
for (int i = 1; i <= n; i++) {
scanf("%d", a+i);
auto it = st[ a[i] ].insert(i).first;
it--;
pre[i] = *it;
}
for (int i = 0; i < n; i++) {
st[i].insert(n+1);
}
for (int i = 1; i <= id(n); i++)
update(i);
while (Q--) {
int op, x, y;
scanf("%d%d%d", &op, &x, &y);
if (op == 0) {
x++;
auto it1 = st[ a[x] ].lower_bound(x), it2 = it1;
it1--, it2++;
int l = *it1, r = *it2;
if (r <= n) {
update(r, l);
}
st[ a[x] ].erase(x);
a[x] = y;
it1 = st[ a[x] ].insert(x).first, it2 = it1;
it1--, it2++;
l = *it1, r = *it2;
update(x, l);
if (r <= n) {
update(r, x);
}
}
else { // op == 1
x++;
// cout << "x = " << x << " , y = " << y << endl;
long long ans = 1ll * (x + y) * (y - x + 1) / 2;
ans -= query(x, y);
printf("%lld\n", ans);
}
}
return 0;
}
/**
5 5
0 1 2 1 4
0 3 3
0 2 4
1 2 5
*/
浙公网安备 33010602011771号