按照套路,我们从左往右枚举交区间的r,并计算方案数
设L[i],R[i]为i前面/后面第一个与它相同的位置,pos为最小的满足[pos,i]中没有重复数的位置,则以r为交区间的右端点的方案数为
∑
i
=
p
o
s
r
(
m
n
{
R
[
i
]
}
−
r
)
(
i
−
m
x
{
L
[
i
]
}
)
\sum_{i=pos}^r(mn\{R[i]\}-r)(i-mx\{L[i]\})
∑i=posr(mn{R[i]}−r)(i−mx{L[i]}),拆开用线段树维护即可,然后mx和mn就和CF997E一样用单调栈维护即可
Code:
#include<bits/stdc++.h>
#define mod 1000000007
#define ll long long
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=1e5+5;
inline int add(ll x,ll y){x+=y;if(x>=mod) x-=mod;return x;}
inline int dec(ll x,ll y){x-=y;if(x<0) x+=mod;return x%mod;}
inline int mul(ll x,ll y){return x*y%mod;}
inline void inc(ll &x,ll y){x+=y;if(x>=mod) x-=mod;}
inline void Dec(ll &x,ll y){x-=y;if(x<0) x+=mod;}
inline ll S(int x){return 1ll*x*(x+1)/2;}
namespace segtree{
struct info{
ll smx,smn,smni,ml;
info(){}
info(ll _smx,ll _smn,ll _smni,ll _ml):smx(_smx),smn(_smn),smni(_smni),ml(_ml){}
friend inline info operator + (const info &a,const info &b){return info(add(a.smx,b.smx),add(a.smn,b.smn),add(a.smni,b.smni),add(a.ml,b.ml));}
};
struct seg{int l,r;info t;ll tmx,tmn;}tr[N<<2];
#define ls tr[k].l
#define rs tr[k].r
#define mid (ls+rs>>1)
inline void pushup(int k){tr[k].t=tr[k<<1].t+tr[k<<1|1].t;}
inline void pushmn(int k,int v){
inc(tr[k].tmn,v);
inc(tr[k].t.ml,mul(v,tr[k].t.smx));
inc(tr[k].t.smn,mul(v,(rs-ls+1)));
inc(tr[k].t.smni,mul(v,dec(S(rs),S(ls-1))));
}
inline void pushmx(int k,int v){
inc(tr[k].tmx,v);
inc(tr[k].t.ml,mul(v,tr[k].t.smn));
inc(tr[k].t.smx,mul(v,(rs-ls+1)));
}
inline void pushdown(int k){
if(tr[k].tmx){
pushmx(k<<1,tr[k].tmx);
pushmx(k<<1|1,tr[k].tmx);
tr[k].tmx=0;
}
if(tr[k].tmn){
pushmn(k<<1,tr[k].tmn);
pushmn(k<<1|1,tr[k].tmn);
tr[k].tmn=0;
}
}
void build(int k,int l,int r){
ls=l;rs=r;tr[k].tmx=tr[k].tmn=0;tr[k].t=info(0,0,0,0);
if(l==r) return;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
void modify(int k,int ql,int qr,int v,int op){
if(rs<ql || ls>qr) return;
if(ql<=ls && rs<=qr) return op?pushmx(k,v):pushmn(k,v);
pushdown(k);
if(qr<=mid) modify(k<<1,ql,qr,v,op);
else if(ql>mid) modify(k<<1|1,ql,qr,v,op);
else modify(k<<1,ql,mid,v,op),modify(k<<1|1,mid+1,qr,v,op);
pushup(k);
}
info query(int k,int ql,int qr){
if(rs<ql || ls>qr) return info(0,0,0,0);
if(ql<=ls && rs<=qr) return tr[k].t;
pushdown(k);
if(qr<=mid) return query(k<<1,ql,qr);
else if(ql>mid) return query(k<<1|1,ql,qr);
else return query(k<<1,ql,mid)+query(k<<1|1,mid+1,qr);
}
}
using namespace segtree;
int n,cnt;
int tong[N],a[N],L[N],R[N],bnd[N];
int stmx[N],stmn[N],topmx=0,topmn=0;
ll ans=0;
int main(){
n=read();build(1,1,n);
for(int i=1;i<=n;i++) a[i]=bnd[i]=read();
sort(bnd+1,bnd+n+1);
cnt=unique(bnd+1,bnd+n+1)-bnd-1;
for(int i=1;i<=n;i++) a[i]=lower_bound(bnd+1,bnd+cnt+1,a[i])-bnd;
for(int i=1;i<=n;i++){
L[i]=tong[a[i]]+1;
tong[a[i]]=i;
}
for(int i=1;i<=cnt;i++) tong[i]=n+1;
for(int i=n;i;i--){
R[i]=tong[a[i]]-1;
tong[a[i]]=i;
}
int pos=1;
for(int i=1;i<=n;i++){
while(topmx && L[i]>=L[stmx[topmx]]) modify(1,stmx[topmx-1]+1,stmx[topmx],dec(0,L[stmx[topmx]]),1),--topmx;
modify(1,stmx[topmx]+1,i,L[i],1);
stmx[++topmx]=i;
while(topmn && R[i]<=R[stmn[topmn]]) modify(1,stmn[topmn-1]+1,stmn[topmn],dec(0,R[stmn[topmn]]),0),--topmn;
modify(1,stmn[topmn]+1,i,R[i],0);
stmn[++topmn]=i;
pos=max(pos,L[i]);
info res=query(1,pos,i);
ll tmp=dec(add(res.smni,mul(i,res.smx)),add(res.ml,mul(dec(S(i),S(pos-1)),i)));
inc(ans,tmp);
}
cout<<ans;
return 0;
}