题解:AT_jsc2019_final_h Distinct Integers
题目链接:AT_jsc2019_final_h Distinct Integers
第一届日本最强程序员学生锦标赛决赛
首先,这道题目要求的是区间有多少个子区间没有重复数字,如果我们记录一下每个数字
现在我们将问题转化成了区间前缀最大值问题,依然考虑使用线段树单侧递归的写法。考虑
考虑
最后考虑 t[id << 1 | 1].ans - t[ls].ans
,往
修改操作可以给每种值开一个集合,记录这种值出现的下标。将
注意一下,如果最大的
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e5 + 9;
struct Node{
int ans, maxn;
} t[N << 2];
int a[N], pre[N], n, q;
int prequery(int id, int l, int r, int ql, int qr){
if(ql <= l && r <= qr)
return t[id].maxn;
int mid = (l + r) >> 1, ans = 0;
if(ql <= mid)
ans = prequery(id << 1, l, mid, ql, qr);
if(qr > mid)
ans = max(ans, prequery(id << 1 | 1, mid + 1, r, ql, qr));
return ans;
}
int pushup(int now, int l, int r, int cmp){
int res = 0;
while(true){
if(l == r){
res += max(t[now].maxn, cmp);
break;
}
int mid = (l + r) >> 1;
if(cmp > t[now << 1].maxn){
res += (mid - l + 1) * cmp;
now = now << 1 | 1;
l = mid + 1;
} else {
res += t[now].ans - t[now << 1].ans;
now = now << 1;
r = mid;
}
}
return res;
}
void build(int id, int l, int r){
if(l == r){
t[id].maxn = t[id].ans = pre[l];
return;
}
int mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
t[id].maxn = max(t[id << 1].maxn, t[id << 1 | 1].maxn);
t[id].ans = t[id << 1].ans + pushup(id << 1 | 1, mid + 1, r, t[id << 1].maxn);
}
void modify(int id, int l, int r, int q, int qx){
if(l == r){
t[id].ans = t[id].maxn = qx;
return;
}
int mid = (l + r) >> 1;
if(q <= mid)
modify(id << 1, l, mid, q, qx);
else
modify(id << 1 | 1, mid + 1, r, q, qx);
t[id].maxn = max(t[id << 1].maxn, t[id << 1 | 1].maxn);
t[id].ans = t[id << 1].ans + pushup(id << 1 | 1, mid + 1, r, t[id << 1].maxn);
}
int query(int id, int l, int r, int ql, int qr){
if(ql <= l && r <= qr)
return pushup(id, l, r, l - 1 ? prequery(1, 1, n, 1, l - 1) : 0);
int mid = (l + r) >> 1, ans = 0;
if(ql <= mid)
ans += query(id << 1, l, mid, ql, qr);
if(qr > mid)
ans += query(id << 1 | 1, mid + 1, r, ql, qr);
return ans;
}
vector <int> s[N];
signed main(){
scanf("%lld%lld", &n, &q);
for(int i = 1; i <= n; i++)
s[i].push_back(0);
for(int i = 1; i <= n; i++){
scanf("%lld", &a[i]);
a[i]++;
s[a[i]].insert(lower_bound(s[a[i]].begin(), s[a[i]].end(), i), i);
pre[i] = *--lower_bound(s[a[i]].begin(), s[a[i]].end(), i);
}
build(1, 1, n);
while(q--){
int opt, x, y;
scanf("%lld%lld%lld", &opt, &x, &y);
x += 1;
y += !opt;
if(opt == 0){
if(upper_bound(s[a[x]].begin(), s[a[x]].end(), x) != s[a[x]].end()){
modify(1, 1, n, *upper_bound(s[a[x]].begin(), s[a[x]].end(), x), *--lower_bound(s[a[x]].begin(), s[a[x]].end(), x));
pre[*upper_bound(s[a[x]].begin(), s[a[x]].end(), x)] = *--lower_bound(s[a[x]].begin(), s[a[x]].end(), x);
}
s[a[x]].erase(lower_bound(s[a[x]].begin(), s[a[x]].end(), x));
s[y].insert(lower_bound(s[y].begin(), s[y].end(), x), x);
pre[x] = *--lower_bound(s[y].begin(), s[y].end(), x);
modify(1, 1, n, x, *--lower_bound(s[y].begin(), s[y].end(), x));
if(upper_bound(s[y].begin(), s[y].end(), x) != s[y].end()){
modify(1, 1, n, *upper_bound(s[y].begin(), s[y].end(), x), x);
pre[*upper_bound(s[y].begin(), s[y].end(), x)] = x;
}
a[x] = y;
} else {
modify(1, 1, n, x, x - 1);
printf("%lld\n", (x + y) * (y - x + 1) / 2 - query(1, 1, n, x, y));
modify(1, 1, n, x, pre[x]);
}
}
return 0;
}
本文来自博客园,作者:JPGOJCZX,转载请注明原文链接:https://www.cnblogs.com/JPGOJCZX/p/18752595
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】