题意:
有一个长度为n的数组,每个数的大小不超过n。定义“好区间”:[l,r]内的最大值+len<=k且区间内不能存在相同的数,k是给定的。询问整个数组中“好区间”的数量。
思路:
比赛的时候不知道如何处理区间不存在相同数字,想想主席树好像可以判断一个区间有没有相同的数字,但是没有了下文。
结束后看了别人的博客,区间的最大值可以直接用st表来处理,而处理无重复数字可以记录每个点向左最远可以延申多少,向右最远可以延申多少。对于一个区间,查询st表找出最大值的位置,然后以这个点划分当前的区间,在左右两部分中选择短的那个区间遍历一边的点,计算另一边的有效长度,并计入答案。
选择短的区间,每次都会暴力小于等于一半的区间,感性理解下时间复杂度大约会在On-Onlog,具体证明不会
参考代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + 5;
const ll INF = 1e18 + 5;
int n,k;
int a[N],ls[N],sz;
int stmaxs[N][20];
int log_2[N];
void build(){
for (int i=1;i<=n;i++){
stmaxs[i][0]=i;
}
for (int j=1;(1<<j)<=n;j++)
for (int i=1;i+(1<<j)-1<=n;i++){
if(a[stmaxs[i][j-1]]>=a[stmaxs[i+(1<<(j-1))][j-1]]){
stmaxs[i][j]=stmaxs[i][j-1];
}
else {
stmaxs[i][j]=stmaxs[i+(1<<(j-1))][j-1];
}
}
}
int query_max(int l,int r)
{
int len=log_2[r-l+1];
if(a[stmaxs[l][len]]>=a[stmaxs[r-(1<<len)+1][len]]){
return stmaxs[l][len];
}
else{
return stmaxs[r-(1<<len)+1][len];
}
}
int pst[N];
int hst[N];
int mp[N];
ll ans;
void solve(int l,int r){
if(l>r)return;
int mid=query_max(l,r);
if(mid-l<r-mid){
for(int i=l;i<=mid;i++){
int len=ls[a[mid]]-k;
int L=i+len-1;
int R=min(r,hst[i]);
L=max(L,mid);
if(R>=L){
ans+=1ll*(R-L+1);
}
}
}
else {
for(int i=mid;i<=r;i++){
int len=ls[a[mid]]-k;
int R=i-len+1;
int L=max(l,pst[i]);
R=min(R,mid);
if(R>=L){
ans+=1ll*(R-L+1);
}
}
}
solve(l,mid-1);
solve(mid+1,r);
}
int main() {
log_2[0]=-1;
for(int i=1;i<N;i++){
log_2[i]=log_2[i>>1]+1;
}
int t;
scanf("%d", &t);
for (int ca = 1; ca <= t; ca++) {
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
ls[i]=a[i];
}
sort(ls+1,ls+1+n);
sz=unique(ls+1,ls+1+n)-ls-1;
for(int i=1;i<=n;i++){
a[i]=lower_bound(ls+1,ls+1+sz,a[i])-ls;
}
build();
for(int i=1;i<=sz;i++){
mp[i]=0;
}
pst[1]=1;
mp[a[1]]=1;
for(int i=2;i<=n;i++){
if(mp[a[i]]){
pst[i]=max(pst[i-1],mp[a[i]]+1);
}
else {
pst[i]=pst[i-1];
}
mp[a[i]]=i;
}
for(int i=1;i<=sz;i++){
mp[i]=0;
}
hst[n]=n;
mp[a[n]]=n;
for(int i=n-1;i>=1;i--){
if(mp[a[i]]){
hst[i]=min(hst[i+1],mp[a[i]]-1);
}
else {
hst[i]=hst[i+1];
}
mp[a[i]]=i;
}
ans=0;
solve(1,n);
printf("%lld\n",ans);
}
return 0;
}