ABC470G
2026-08-08 21:41:58
发布于:广东
场G了????!!!
我已严肃会线段树!
题目本质上是让我们求一个这么个东西
遇到这种双层循环+求区间的操作,第一想法是固定,计算的贡献。
考虑从到所产生的影响,我们失去了,而下一个我们记为(若没有就是),我们可能影响的区间是!
考虑情况:
1.若这个区间的最大值都比还小,显然对这段区间无影响。
2.反之,相当于做一个区间覆盖,用更新这个区间,所以用线段树维护!
所以就做完了,时间复杂度
#include <iostream>
#include <vector>
#include <bits/stdc++.h>
using namespace std;
namespace CZW {
#define endl "\n"
#define vec std::vector
#define pb push_back
#define eb emplace_back
using ll = long long;
using ull = unsigned long long;
using i128 = __int128;
void init() {
// freopen("1.in","r",stdin);
// freopen("my.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
}
constexpr int N = 3e5 + 5;
int a[N], nxt[N], lst[N];
int cur[N], cnt[N];
namespace Seg {
struct Node {
int len;
ll sum;
int tag, mi, ma;
#define len(rt) tr[rt].len
#define sum(rt) tr[rt].sum
#define tag(rt) tr[rt].tag
#define mi(rt) tr[rt].mi
#define ma(rt) tr[rt].ma
} tr[N << 2];
void up(int rt) {
sum(rt) = sum(rt << 1) + sum(rt << 1 | 1);
mi(rt) = min(mi(rt << 1), mi(rt << 1 | 1));
ma(rt) = max(ma(rt << 1), ma(rt << 1 | 1));
}
void build(int rt, int l, int r) {
tr[rt] = {r - l + 1, 0, -1, 0, 0};
if (l == r) {
sum(rt) = mi(rt) = ma(rt) = cur[l];
return ;
}
int mid = (l + r) >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
up(rt);
}
void change(int rt, int v) {
sum(rt) = 1ll * v * len(rt);
mi(rt) = ma(rt) = tag(rt) = v;
}
void down(int rt) {
if (~tag(rt)) {
change(rt << 1, tag(rt));
change(rt << 1 | 1, tag(rt));
tag(rt) = -1;
}
}
void update(int rt, int l, int r, int x, int y, int v) {
if (r < x || l > y || ma(rt) <= v) return ;
if (l >= x && r <= y && mi(rt) > v) {
change(rt, v);
return ;
}
int mid = (l + r) >> 1;
down(rt);
if (x <= mid) update(rt << 1, l, mid, x, y, v);
if (y > mid) update(rt << 1 | 1, mid + 1, r, x, y, v);
up(rt);
}
ll query(int rt, int l, int r, int x, int y) {
if (l >= x && r <= y) return sum(rt);
down(rt);
int mid = (l + r) >> 1;
ll res = 0;
if (x <= mid) res += query(rt << 1, l, mid, x, y);
if (y > mid) res += query(rt << 1 | 1, mid + 1, r, x, y);
return res;
}
}
void Main() {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
int pos = 0;
for (int i = 1; i <= n; ++i) {
++cnt[a[i]];
while (pos <= n && cnt[pos]) ++pos;
cur[i] = pos;
}
Seg::build(1, 1, n);
for (int i = 0; i <= n + 1; ++i) lst[i] = n + 1;
for (int i = n; i >= 1; --i) {
nxt[i] = lst[a[i]];
lst[a[i]] = i;
}
ll ans = 0;
for (int l = 1; l <= n; ++l) {
ans += Seg::query(1, 1, n, l, n);
int r = nxt[l] - 1;
if (l < r) Seg::update(1, 1, n, l + 1, r, a[l]);
}
cout << ans;
}
}
int main() {
CZW::init();
int Test = 1;
// cin >> Test;
while (Test--)
CZW::Main();
return 0;
}
全部评论 11
- 置顶
www,大佬们/bx
1周前 来自 广东
1 @古希腊掌管AC和WA的神 这里有你最喜欢的线段树题目
1周前 来自 上海
1您怎么这么强!
1周前 来自 浙江
1您怎么这么强!
1周前 来自 浙江
1@cjdst踢一下,调70min没绷住
1周前 来自 广东
1您怎么这么强!
1周前 来自 江西
1您咋这强。
1周前 来自 广东
1您怎么这么强!
1周前 来自 上海
1tql,orz%%%
1周前 来自 浙江
1ddddddd
1周前 来自 广东
1您怎么这么强!
1周前 来自 江西
0



































有帮助,赞一个