正题
P4755
题目大意
给你n个数,问你有多少对二元组 (i,j)(i,j)(i,j) 满足 i≤ji\leq ji≤j 且 ai×aj≤maxi=ijaia_i\times a_j\leq max_{i=i}^ja_iai×aj≤maxi=ijai
解题思路
考虑对原数组构建笛卡尔树,树中左右子树之间的二元组所取得的max就是当前节点
考虑启发式合并,把大的子树存到树状数组,然后小的子树直接暴力计算答案
时间复杂度 O(nlog2n)O(n\ log^2\ n)O(n log2 n)
code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 100100
using namespace std;
ll n,m,ans,a[N],c[N],g[N],b[N],lg[N],f[N][20];
ll get(ll l,ll r)
{ll g=lg[r-l+1];if(a[f[l][g]]>a[f[r-(1<<g)+1][g]])return f[l][g];else return f[r-(1<<g)+1][g];
}
void add(ll x)
{x=upper_bound(b+1,b+1+m,x)-b-1;for(;x<=m;x+=x&-x)c[x]++;return;
}
ll ask(ll x)
{x=upper_bound(b+1,b+1+m,x)-b-1;ll sum=0;for(;x;x-=x&-x)sum+=c[x];return sum;
}
void dfs(ll l,ll r)
{if(l>r)return;ll x=get(l,r);if(x-l<r-x){g[x]=ask(1);for(ll i=l;i<x;++i)g[i]=ask(a[x]/a[i]);dfs(x+1,r);add(a[x]);for(ll i=l;i<x;++i)ans+=ask(a[x]/a[i])-g[i];ans+=ask(1)-g[x];dfs(l,x-1);}else{g[x]=ask(1);for(ll i=x+1;i<=r;++i)g[i]=ask(a[x]/a[i]);dfs(l,x-1);add(a[x]);for(ll i=x+1;i<=r;++i)ans+=ask(a[x]/a[i])-g[i];ans+=ask(1)-g[x];dfs(x+1,r);}return;
}
int main()
{scanf("%lld",&n);for(ll i=1;i<=n;++i){scanf("%lld",&a[i]);b[i]=a[i];f[i][0]=i;}sort(b+1,b+1+n);m=unique(b+1,b+1+n)-b-1;for(ll i=2;i<=n;++i)lg[i]=lg[i>>1]+1;for(ll j=1;j<=16;++j)for(ll i=1;i<=n-(1<<j-1);++i)if(a[f[i][j-1]]>a[f[i+(1<<j-1)][j-1]])f[i][j]=f[i][j-1];else f[i][j]=f[i+(1<<j-1)][j-1];dfs(1,n);printf("%lld",ans);return 0;
}