正题

题目链接:https://www.luogu.com.cn/problem/P4755


题目大意

\(n\)个数字的一个序列,求有多少个点对\(i,j\)满足\(a_i\times a_j\leq max\{a_k\}(k\in[l,r])\)


解题思路

如果构建一棵笛卡尔树的话那么两个点之间的\(max\)就在笛卡尔树的\(LCA\)位置。

所以对于每个位置维护一个线段树,然后每次暴力枚举小的那棵子树在大子树的线段树中查询即可。然后线段树合并或者启发式合并上去就好了。

建笛卡尔树的时候用\(\text{RMQ}\)查询区间最大值然后递归下去就好了。

当然因为是乘法所以小的那个值域不会超过\(\sqrt{10^9}\)所以也可以树状数组+启发式合并。

这里写的是线段树的做法,时间复杂度都是\(O(n\log^2 n)\)

注意\(1\)要特判就好了


code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10,L=20;
int n,a[N],lg[N],f[N][L+1],inf;
long long ans;
struct Seg_Tree{
int cnt,w[N<<6],ls[N<<6],rs[N<<6];
void Change(int &x,int L,int R,int pos,int val){
if(!x)x=++cnt;w[x]+=val;
if(L==R)return;
int mid=(L+R)>>1;
if(pos<=mid)Change(ls[x],L,mid,pos,val);
else Change(rs[x],mid+1,R,pos,val);
return;
}
int Ask(int x,int L,int R,int l,int r){
if(!x||l>r)return 0;
if(L==l&&R==r)return w[x];
int mid=(L+R)>>1;
if(r<=mid)return Ask(ls[x],L,mid,l,r);
if(l>mid)return Ask(rs[x],mid+1,R,l,r);
return Ask(ls[x],L,mid,l,mid)+Ask(rs[x],mid+1,R,mid+1,r);
}
int Merge(int x,int y,int L,int R){
if(!x||!y)return x+y;
int mid=(L+R)>>1;w[x]+=w[y];
if(L==R)return x;
ls[x]=Merge(ls[x],ls[y],L,mid);
rs[x]=Merge(rs[x],rs[y],mid+1,R);
return x;
}
}T;
int Ask(int l,int r){
int z=lg[r-l+1];
int x=f[l][z],y=f[r-(1<<z)+1][z];
return (a[x]>=a[y])?x:y;
}
int solve(int l,int r){
if(l>r)return 0;
int x=Ask(l,r),ls,rs;
ls=solve(l,x-1);
rs=solve(x+1,r);
if(ls)ans+=T.Ask(ls,1,inf,1,1);
if(rs)ans+=T.Ask(rs,1,inf,1,1);
if(x-l<=r-x){
for(int i=l;i<x;i++)
ans+=T.Ask(rs,1,inf,1,a[x]/a[i]);
}
else{
for(int i=x+1;i<=r;i++)
ans+=T.Ask(ls,1,inf,1,a[x]/a[i]);
}
ls=T.Merge(ls,rs,1,inf);
T.Change(ls,1,inf,a[x],1);
return ls;
}
int main()
{
// printf("%d\n",sizeof(T)>>20);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
inf=max(inf,a[i]);
ans+=(a[i]==1);
f[i][0]=i;
}
inf=1e9;
for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++){
int x=f[i][j-1],y=f[i+(1<<j-1)][j-1];
if(a[x]>=a[y])f[i][j]=x;
else f[i][j]=y;
}
solve(1,n);
printf("%lld",ans);
return 0;
}

最新文章

  1. Web 开发人员和设计师必读文章推荐【系列三十】
  2. php基础入门
  3. Docker容器基础知识学习
  4. iOS UIButton添加圆角,添加边框
  5. .net中的&quot;异步&quot;-手把手带你体验
  6. jstring 和char 之间的转换方法
  7. Android相关类关系
  8. python 多线程 paramiko实现批量命令输入输出
  9. swust oj 237
  10. Flask-----Flask里引用哈希密码
  11. 解决pycharm下代码报错的问题
  12. src-d engine 强大的git 历史分析工具
  13. Linux应急处理操作手册
  14. ASP.NET5之客户端开发:Grunt和Gulp构建工具在Visual Studio 2015中的高效的应用
  15. android框架----&gt;下沉文字Titanic的使用
  16. 牛客网习题剑指offer之数值的整数次方
  17. 服务遇到错误。很可能由IncludeExceptionDetailInFaults=true创建的ExceptionDetail,其值为:System.ArgumentException:指定的值还有无效的控制字符
  18. leecode刷题(13) -- 字符串中的第一个唯一字符
  19. 7、Java并发编程:深入剖析ThreadLocal
  20. 初入Spring-boot(一)

热门文章

  1. java实现随机字母数字验证码
  2. 多线程之旅(9)_如何安全的取消正在执行的线程——附C#源码
  3. vue2.0中模拟数据的配置
  4. request库的简单使用
  5. shiro(二)
  6. Map 综述(一):彻头彻尾理解 HashMap
  7. servlet通过响应头Content-Disposition实现文件下载效果
  8. Dijkstra链路状态选路算法
  9. Python 3.10 is coming!
  10. RabbitMq安装(单点与集群)rabbitMq以及状态查询