[题解]CF875D High Cry
我们令:
- \(L[i]\) 为最小的 \(j\le i\) 使得 \(\max a[j\sim (i-1)]<a[i]\)。
- \(R[i]\) 为最大的 \(j\ge i\) 使得 \(\max a[(i+1)\sim j]\le a[i]\)。
可以用单调栈在 \(O(n)\) 内求出。
这样我们就大致刻画出了以 \(a_i\) 为最大值的区间 \([l,r]\) 需要满足的条件之一:\(l\in[L[i],i],r\in[i,R[i]]\)。
注意:如果多个值同时作为一个区间的最大值,我们必须保证答案仅由其中一个进行统计。这也是为什么 \(L,R\) 的定义是一个 \(<\) 一个 \(\le\)(很像 ABC407F):
- 如果都是 \(<\),那么此贡献会被忽略;
- 如果都是 \(\le\),那么此贡献会在每个最大值处都统计一次,造成重复。
接下来,我们仅需限制 \([l,r]\) 的区间或 \(> \max a[l\sim r]\)。
显然固定 \(l\) 不动时,区间或随 \(r\) 不降;固定 \(r\) 不动时,区间或随 \(l\) 不增。
换句话说:
- 我们一定可以找到一个最小的 \(l'\ge L\),使得 \([l',i]\) 的区间或 \(\le \max\)。
- 我们一定可以找到一个最大的 \(r'\le R\),使得 \([i,r']\) 的区间或 \(\le \max\)。
可以用 ST 表 + 二分或倍增 在 \(O(\log n)\) 内求出。
\([L,R]\) 所有包含 \(i\) 的子区间中,是 \([l',r']\) 子区间的,都有区间或 \(=\max\);不是 \([l',r']\) 子区间的,都有区间或 \(>\max\)。
后者又可以进一步讨论:
- \(l\in [L,l'),r\in [i,r']\)。对答案贡献为 \((l'-L)\times(r'-i+1)\)。
- \(l\in [l',i],r\in (r',R]\)。对答案贡献为 \((i-l'+1)\times(R-r')\)。
- \(l\in [L,l'),r\in (r',R]\)。对答案贡献为 \((l'-L)\times(R-r')\)。
三种情况累加起来就可以了。
时间复杂度 \(O(n\log n)\)。
代码实现求 \(l',r'\) 用了线段树,所以时间复杂度是 \(O(n\log^2 n)\)。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define lc (x<<1)
#define rc (x<<1|1)
using namespace std;
const int N=2e5+10;
int n,a[N],lef[N],rig[N],st[N],top,ans;
struct SEG{
int sum[N<<2];
void build(int x,int l,int r){
if(l==r) return sum[x]=a[l],void();
int mid=(l+r)>>1;
build(lc,l,mid),build(rc,mid+1,r);
sum[x]=sum[lc]|sum[rc];
}
int qry(int x,int a,int b,int l,int r){
if(a>b) return 0;
if(a<=l&&r<=b) return sum[x];
int mid=(l+r)>>1,ans=0;
if(a<=mid) ans|=qry(lc,a,b,l,mid);
if(b>mid) ans|=qry(rc,a,b,mid+1,r);
return ans;
}
}tr;
signed main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
tr.build(1,1,n);
for(int i=1;i<=n;i++){
while(top&&a[st[top]]<a[i]) top--;
lef[i]=top?st[top]+1:1,st[++top]=i;
}
top=0;
for(int i=n;i;i--){
while(top&&a[st[top]]<=a[i]) top--;
rig[i]=top?st[top]-1:n,st[++top]=i;
}
for(int i=1,pl,pr;i<=n;i++){
pl=pr=i;
for(int j=18;~j;j--){
if(pl-(1<<j)>=lef[i]&&tr.qry(1,pl-(1<<j),i,1,n)==a[i]){
pl-=(1<<j);
}
if(pr+(1<<j)<=rig[i]&&tr.qry(1,i,pr+(1<<j),1,n)==a[i]){
pr+=(1<<j);
}
}
ans+=(pl-lef[i])*(pr-i+1)+(rig[i]-pr)*(i-pl+1)+(pl-lef[i])*(rig[i]-pr);
}
cout<<ans<<"\n";
return 0;
}
浙公网安备 33010602011771号