题目大意
给定一个n个数的数组
1≤n≤5×105,1≤ai≤109
题目分析
这题是一个很优美的暴力。
为了方便求出区间最大值,我们先建出笛卡尔树。
考虑枚举笛卡尔树上每一个点,显然可以得到它作为最大值的区间。
如果我们枚举这个区间的左半部分的一个数,结合当前最大值,我们就知道右半区间的合法的数的取值范围。也就是我们只需要查询右半区间有多少个数小于等于某数即可。
但是这样显然是O(n2)的,但是不虚,使用类似启发式合并的想法,如果右边比左边长度小,我们就枚举右边!这样每次枚举长度不会超过整个区间的一半!也就是说枚举的复杂度是O(nlog2n)的!
至于查询,你可以选择打一个主席树在线查。当然也可以先把所有区间询问变为两个前缀询问相减,然后先存下来,遍历完笛卡尔树之后再统一使用树状数组计算。
时间复杂度O(nlog22n)。
注意特判当前最大值和别的数组合造成的贡献。
代码实现
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cctype>
using namespace std;
typedef long long LL;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N=500050;
const int LGN=20;
const int Q=N*LGN<<1;
struct query
{
int x,a,sign;
}qs[Q];
bool operator<(query p,query q){return p.x<q.x;}
struct D
{
int key,id;
}srt[N];
bool operator<(D x,D y){return x.key<y.key;}
int A[N],fa[N],son[N][2],stack[N],lab[N],num[N];
int n,q,top,root,idx;
LL ans;
inline int lowbit(int x){return x&-x;}
struct Fenwick_tree
{
int num[N];
void modify(int x,int delta){for (;x<=idx;x+=lowbit(x)) num[x]+=delta;}
int query(int x)
{
int ret=0;
for (;x;x-=lowbit(x)) ret+=num[x];
return ret;
}
}t;
void build()
{
for (int i=1;i<=n;i++)
{
while (top&&A[stack[top]]<A[i]) fa[i]=stack[top-1],fa[son[i][0]]=stack[top],son[stack[top]][1]=son[i][0],son[i][0]=stack[top],fa[stack[top--]]=i;
if (top) son[stack[top]][1]=i;
fa[stack[++top]=i]=stack[top-1];
if (!fa[i]) root=i;
}
}
int st[N][3];
int tp;
int vis[N];
void dfs()
{
int x,l,r;
st[++tp][0]=root,st[tp][1]=1,st[tp][2]=n;
while (tp)
{
x=st[tp][0],l=st[tp][1],r=st[tp][2];
if (!x)
{
tp--;
continue;
}
if (!vis[x])
{
if (x-l<r-x)
for (int i=l;i<=x;i++)
{
qs[++q].x=r,qs[q].a=A[x]/A[i],qs[q].sign=1;
qs[++q].x=x,qs[q].a=A[x]/A[i],qs[q].sign=-1;
ans+=(i<x&&A[i]==1);
}
else
for (int i=x;i<=r;i++)
{
qs[++q].x=x-1,qs[q].a=A[x]/A[i],qs[q].sign=1;
qs[++q].x=l-1,qs[q].a=A[x]/A[i],qs[q].sign=-1;
ans+=(i>x&&A[i]==1);
}
vis[x]++;
}
else if (vis[x]==1)
{
vis[x]++;
st[++tp][0]=son[x][0],st[tp][1]=l,st[tp][2]=x-1;
continue;
}
else
{
vis[x]++;
st[tp][0]=son[x][1],st[tp][1]=x+1,st[tp][2]=r;
}
}
}
void pre()
{
for (int i=1;i<=n;i++) srt[i].key=A[i],srt[i].id=i;
sort(srt+1,srt+1+n);
idx=0;
for (int i=1;i<=n;i++) num[lab[srt[i].id]=idx+=srt[i].key!=srt[i-1].key]=srt[i].key;
}
int pos(int v)
{
int l=1,r=idx,mid,ret=0;
while (l<=r)
{
mid=l+r>>1;
if (num[mid]<=v) l=(ret=mid)+1;
else r=mid-1;
}
return ret;
}
void calc()
{
sort(qs+1,qs+1+q);
for (int cur=1,i=1;i<=q;i++)
{
while (cur<=n&&cur<=qs[i].x) t.modify(lab[cur++],1);
ans+=qs[i].sign*t.query(pos(qs[i].a));
}
}
int main()
{
freopen("arrpairs.in","r",stdin),freopen("arrpairs.out","w",stdout);
n=read();
for (int i=1;i<=n;i++) A[i]=read();
build(),ans=0,dfs(),pre(),calc();
printf("%lld\n",ans);
fclose(stdin),fclose(stdout);
return 0;
}