题目大意
求有多少个区间满足权值为i的数量在[li,ri]内。
扫一扫
我们枚举区间右端点,左端点的可取范围是一段区间。
尝试用两个堆维护左端点的最大值和最小值。
对于第i种权值,我们可以通过指针跳跳跳获得在位置i时左端点的左界和右界,所以一个堆保存所有权值的左界另一个保存右界。
注意l=0以及r=0的情况。
#include<cstdio>
#include<algorithm>
#include<set>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long LL;
const int maxn=200000+10;
multiset<int> s1,s2;
int L[maxn],R[maxn],ll[maxn],rr[maxn],fi[maxn],right[maxn],id[maxn],cnt[maxn],a[maxn];
int i,j,k,l,r,t,n,m;
LL ans;
int read(){
int x=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
int main(){
freopen("survey.in","r",stdin);freopen("survey.out","w",stdout);
n=read();m=read();
fo(i,1,n) a[i]=read();
fo(i,1,m) L[i]=read(),R[i]=read();
fo(i,1,m) cnt[i]=1;
fd(i,n,1){
right[i]=fi[a[i]];
fi[a[i]]=i;
}
fo(i,1,n) id[i]=++cnt[a[i]];
id[0]=1;
fo(i,1,m){
ll[i]=1;
s1.insert(-ll[i]);
if (L[i]){
rr[i]=0;
s2.insert(rr[i]);
}
}
fo(i,1,n){
t=a[i];
if (L[t]){
while (id[i]-id[rr[t]]+1>L[t]){
s2.erase(s2.find(rr[t]));
if (!rr[t]) rr[t]=fi[t];else rr[t]=right[rr[t]];
s2.insert(rr[t]);
}
}
while (id[i]-id[ll[t]-1]+1>R[t]+1){
s1.erase(s1.find(-ll[t]));
if (ll[t]==1) ll[t]=fi[t]+1;else ll[t]=right[ll[t]-1]+1;
s1.insert(-ll[t]);
}
l=-(*s1.begin());
if (!s2.empty()) r=*s2.begin();else r=i;
if (l<=r) ans+=(LL)(r-l+1);
}
printf("%lld\n",ans);
}