题解:AT_abc470_g [ABC470G] ΣШX
前情提要
你以飞快的速度写完了 ABCDEF。
你看了 G。
你发现 G 你貌似会。
你不摆了。你开想。
思路
啊。是这么个东西。
好传奇啊。
不过我记得
也就是说在一个区间随便加数,区间
啊貌似可以双指针状物。
总之先固定
哦等会,我记得好像如果区间每缺少一个值,若区间只有一个值,
哦这很好。
我们可以暴力算出左端点
我们可以枚举左端点然后算出每一个右端点对应的
那么我们可以查一下下一个值也为
我们可以对右端点属于
注意是开区间。
这是好做的。
类似这个题,并根据我之前写的题解,我们可以写出线段树二分或线段树上二分。
等会这不是我之前模拟赛的题吗。
我赢了!
啊我要赢了吗?!
#include <bits/stdc++.h>
#define SACRIFICING using
#define THE namespace
#define ROOK std
SACRIFICING THE ROOK;
typedef long long ll;
int n;
int a[300009];
vector<int>de[300009];
bool vis[300009];
int sd[300009];
int lz[1200009];
struct node{
int maxn;
int minn;
ll sum;
}tr[1200009];
inline void puup(int pos){
tr[pos].maxn=max(tr[pos<<1].maxn,tr[pos<<1|1].maxn);
tr[pos].minn=min(tr[pos<<1].minn,tr[pos<<1|1].minn);
tr[pos].sum=tr[pos<<1].sum+tr[pos<<1|1].sum;
}
inline void pudo(int pos,int l,int r){
if(lz[pos]!=-1){
int mid=(l+r)>>1;
lz[pos<<1]=lz[pos<<1|1]=lz[pos];
tr[pos<<1].sum=1ll*(mid-l+1)*lz[pos];
tr[pos<<1|1].sum=1ll*(r-mid)*lz[pos];
tr[pos<<1].minn=tr[pos<<1|1].minn=tr[pos<<1].maxn=tr[pos<<1|1].maxn=lz[pos];
lz[pos]=-1;
}
}
inline void build(int pos,int l,int r){
lz[pos]=-1;
tr[pos].maxn=0;
tr[pos].minn=400009;
if(l>r)return ;
if(l==r){
tr[pos].maxn=tr[pos].minn=tr[pos].sum=sd[l];
return ;
}
build(pos<<1,l,(l+r)>>1);
build(pos<<1|1,(l+r)/2+1,r);
puup(pos);
}
inline ll que(int pos,int l,int r,int sl,int sr){
if(l>r||l>sr||r<sl)return 0;
if(l>=sl&&r<=sr){
return tr[pos].sum;
}
pudo(pos,l,r);
return que(pos<<1,l,(l+r)>>1,sl,sr)+que(pos<<1|1,(l+r)/2+1,r,sl,sr);
}
inline void upd(int pos,int l,int r,int sl,int sr,int k){
// cout<<tr[pos].maxn<<' '<<l<<" "<<r<<'\n';
if(l>r||l>sr||r<sl||tr[pos].maxn<=k)return ;
if(l>=sl&&r<=sr&&tr[pos].minn>=k){
tr[pos].maxn=tr[pos].minn=k;
tr[pos].sum=1ll*(r-l+1)*k;
//cout<<l<<' '<<r<<' '<<k<<'\n';
lz[pos]=k;
return ;
}
pudo(pos,l,r);
upd(pos<<1,l,(l+r)>>1,sl,sr,k);
upd(pos<<1|1,(l+r)/2+1,r,sl,sr,k);
puup(pos);
}
ll ans=0;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=n;i>=1;i--){
de[a[i]].push_back(i);
}
int curans=0;
for(int i=1;i<=n;i++){
vis[a[i]]=1;
for(;curans<=n;curans++){
if(!vis[curans])break;
}
sd[i]=curans;
}
build(1,1,n);
ans+=tr[1].sum;
for(int i=2;i<=n;i++){
de[a[i-1]].pop_back();
int kf;
if(!de[a[i-1]].empty())kf=de[a[i-1]].back();
else kf=n+1;
//cout<<i<<' '<<kf<<' '<<a[i-1]<<'\n';
upd(1,1,n,i,kf-1,a[i-1]);
ans+=que(1,1,n,i,n);
}
printf("%lld",ans);
return 0;
}
后记
少年,你醒了。
想啥呢。
你的 F 都因为猎奇错误而炸了。
然后你没看 G。
醒醒,孩子。
你的那个模拟赛题目的题解代码正解也写错了。
离黄 perf 最近的一次。
离 AK 最近的一次。
我想哭。
啊。我的黄 perf——
啊啊啊啊。(撒泼打滚)
所以求赞我的 CDEFG 题解。