ABC346G
题意:
给定一个
题意很明确,如何解决?
暴力:
直接
莫队:
由于发现对于一个区间
inline void upd(int x){
mp[a[x]]--;
}
inline bool que(int x){
if(mp[a[x]]>=1){
return false;
}
return true;
}
这样做是
正解:
考虑用
但是这样做会发现有很多数会重复计算,所有可以用扫描线算法每个
具体的:
设
那么有形如双指针的方法枚举左端点
我们要在每次
然后发现这个并集大小的维护实际上是要我们支持区间加 / 减查询区间非 0
数个数,同时保证任意时刻所有数非负。于是直接把扫描线维护矩形面积并的线段树拿过来即可。具体地,维护区间内最小值及其个数,查询时若区间最小值为 0
,则返回区间长度减去最小值个数,否则返回区间长度。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,a[N],l[N],r[N];
int mp[N];
long long ans=0;
struct edge{
int ll,rr,hh,ff;
}e[N<<1];
int cnt;
inline int ls(int p){
return p<<1;
}
inline int rs(int p){
return p<<1|1;
}
void add(int l,int r,int h,int f){
e[++cnt].ll=l;
e[cnt].rr=r;
e[cnt].hh=h;
e[cnt].ff=f;
}
bool operator <(const edge &a,const edge &b){
if(a.hh==b.hh)return a.ff>b.ff;
return a.hh<b.hh;
}
struct node{
int sum,len;
}tr[N<<2];
void pushup(int p,int l,int r){
if(tr[p].sum) tr[p].len=r-l+1;
else if(l==r) tr[p].len=0;
else tr[p].len=tr[ls(p)].len+tr[rs(p)].len;
}
void update(int p,int l,int r,int L,int R,int val){
if(L<=l&&r<=R){
tr[p].sum+=val;
pushup(p,l,r);
return ;
}
int mid=(l+r)>>1;
if(L<=mid)update(ls(p),l,mid,L,R,val);
if(R>mid) update(rs(p),mid+1,r,L,R,val);
pushup(p,l,r);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
l[i]=mp[a[i]]+1;
mp[a[i]]=i;
}
for(int i=1;i<N;i++) mp[i]=0;
for(int i=n;i>=1;i--){
if(mp[a[i]])r[i]=mp[a[i]]-1;
else r[i]=n;
mp[a[i]]=i;
}
for(int i=1;i<=n;i++){
add(i,r[i]+1,l[i],1);
add(i,r[i]+1,i+1,-1);
}
sort(e+1,e+1+cnt);
for(int i=1;i<cnt;i++){
update(1,1,n+1,e[i].ll,e[i].rr-1,e[i].ff);
ans+=1ll*tr[1].len*(e[i+1].hh-e[i].hh);
}
cout<<ans;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探