题目传送门

题目大意

给出一个 \(n\) 个点的序列 \(a_{1,2,...,n}\) ,问有多少对点对 \((i,j)\) 满足 \(a_i\times a_j\le a_k(i\le k\le j)\)。

\(n\le 10^5,1\le a_i\le 10^9\)

思路

话说为什么裸的笛卡尔树上分治可以骗到 \(90\) 分啊???

首先不难看出一个比较 naive 的做法,就是说我们可以考虑最大堆得笛卡尔树上的一个子树,如果左端点在左子树,右端点在右子树,那么最大值就是根,然后其实就是统计 \(\lfloor\frac{k}{a_i}\rfloor\) ,其中 \(k\) 表示根的值。具体实现就是直接摊平然后当序列搞就好了,不过你可以发现其实不需要摊平。

然后我们发现这样做时间复杂度在单调的序列中时间复杂度就会降到 \(\Theta(n^2\log n)\),我们考虑启发式合并,即是说我们每次选较小的子树进行查询,然后区间小于等于某个数的个数可以使用主席树进行维护。

考虑这样做的时间复杂度,我们考虑对于每个点的查询次数,可以想到,它作为最小值得时候爬树的时候每次子树大小都至少扩大一倍,于是最多就被访问到 \(\log n\) 次,所以总时间复杂度就是 \(\Theta(n\log^2 n)\) 。

\(\texttt{Code}\)

#include <bits/stdc++.h>
using namespace std; #define Int register int
#define ll long long
#define MAXN 100005 char buf[1 << 21],*p1 = buf,*p2 = buf;
#define getchar() ((p1 == p2 && (p2 = (p1 = buf) + fread(buf,1,1 << 21,stdin))) ? EOF : *p1 ++)
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} ll ans;
int n,top,len,ls[MAXN],rs[MAXN],val[MAXN],tur[MAXN],sta[MAXN],root[MAXN]; void buildTree (){
for (Int i = 1;i <= n;++ i){
int tmp = top;
while (top && val[sta[top]] < val[i]) -- top;
if (top) rs[sta[top]] = i;
if (top < tmp) ls[i] = sta[top + 1];
sta[++ top] = i;
}
} struct Segment{
#define LOG 21
int cnt,sum[MAXN * LOG],ls[MAXN * LOG],rs[MAXN * LOG];
void modify (int &x,int y,int l,int r,int pos){
x = ++ cnt,sum[x] = sum[y] + 1,ls[x] = ls[y],rs[x] = rs[y];
if (l == r) return ;
int mid = (l + r) >> 1;
if (pos <= mid) modify (ls[x],ls[y],l,mid,pos);
else modify (rs[x],rs[y],mid + 1,r,pos);
}
int query (int x,int l,int r,int tl,int tr){
if (!x || (l >= tl && r <= tr)) return sum[x];
int mid = (l + r) >> 1,res = 0;
if (tl <= mid) res += query (ls[x],l,mid,tl,tr);
if (tr > mid) res += query (rs[x],mid + 1,r,tl,tr);
return res;
}
int query (int l,int r,int tl,int tr){
return query (root[r],1,len,tl,tr) - query (root[l - 1],1,len,tl,tr);
}
}Tree; void divide (int x,int l,int r){
if (!ls[x] && !rs[x]) return ans += (tur[val[x]] == 1),void ();
if (x - l < r - x){
for (Int i = l;i <= x;++ i){
int ind = upper_bound (tur + 1,tur + len + 1,tur[val[x]] / tur[val[i]]) - tur - 1;
if (!ind) continue;
ans += Tree.query (x,r,1,ind);
}
}
else{
for (Int i = x;i <= r;++ i){
int ind = upper_bound (tur + 1,tur + len + 1,tur[val[x]] / tur[val[i]]) - tur - 1;
if (!ind) continue;
ans += Tree.query (l,x,1,ind);
}
}
if (ls[x]) divide (ls[x],l,x - 1);
if (rs[x]) divide (rs[x],x + 1,r);
} signed main(){
read (n);
for (Int i = 1;i <= n;++ i) read (val[i]),tur[i] = val[i];
sort (tur + 1,tur + n + 1),len = unique (tur + 1,tur + n + 1) - tur - 1;
for (Int i = 1;i <= n;++ i) val[i] = lower_bound (tur + 1,tur + len + 1,val[i]) - tur;
buildTree ();for (Int i = 1;i <= n;++ i) Tree.modify (root[i],root[i - 1],1,len,val[i]);
divide (sta[1],1,n),write (ans),putchar ('\n');
return 0;
}

题解 Beautiful Pair的更多相关文章

  1. 【题解】P4755 Beautiful Pair(启发式合并的思路+分治=启发式分治)

    [题解]P4755 Beautiful Pair upd: 之前一个first second烦了,现在AC了 由于之前是直接抄std写的,所以没有什么心得体会,今天自己写写发现 不知道为啥\(90\) ...

  2. 「LGR-049」洛谷7月月赛 D.Beautiful Pair

    「LGR-049」洛谷7月月赛 D.Beautiful Pair 题目大意 : 给出长度为 \(n\) 的序列,求满足 \(i \leq j\) 且 $a_i \times a_j \leq \max ...

  3. [luogu4755]Beautiful Pair

    [luogu4755]Beautiful Pair luogu 第一次写最大值分治感觉有点丑 每次找到最大值mid,扫小的一边,主席树查大的一边小于等于\(\frac{a[mid]}{a[i]}\)的 ...

  4. Luogu4755 Beautiful Pair 最值分治、主席树

    传送门 整天做一些模板题感觉药丸 设\(val_i\)表示第\(i\)个位置的值 看到区间最大值考虑最值分治.对于当前的区间\([l,r]\),找到区间最大值\(mid\),递归\([l,mid-1] ...

  5. P4755 Beautiful Pair (分治 + 主席树)

    题意:1e5的数组 计算有多少对 ai * aj <= max(ai ai+1...aj-1 aj) 题解:在处理这种涉及到区间极值的题时 好像是个套路分治 从级值中间分成两个区间 从区间短的那 ...

  6. 洛谷 P4755 - Beautiful Pair(主席树+分治+启发式优化)

    题面传送门 wssb,我紫菜 看到这类与最大值统计有关的问题可以很自然地想到分治,考虑对 \([l,r]\) 进行分治,求出对于所有 \(l\le x\le y\le r\) 的点对 \((x,y)\ ...

  7. luoguP4755 Beautiful Pair

    https://www.luogu.org/problemnew/show/P4755 考虑分治,在 [l, r] 区间中用线段树找到最大的一个点,处理经过它的可行数对的个数,统计个数可以离线树状数组 ...

  8. Luogu 4755 Beautiful Pair

    分治 + 主席树. 设$solve(l, r)$表示当前处理到$[l, r]$区间的情况,我们可以找到$[l, r]$中最大的一个数的位置$mid$,然后扫一半区间计算一下这个区间的答案. 注意,这时 ...

  9. P4755 Beautiful Pair

    题目 洛谷 做法 \(i≤x≤j,a[i]<\frac{a[x]}{a[j]}\) 考虑\(a[x]\)的贡献,单调栈预处理\(L,R\)能作为最大值的区间 枚举一端点,仅需另一端点满足条件即可 ...

随机推荐

  1. Windows10下MySQL的安装

    简单介绍一下MySQL的安装 官方网址:https://www.mysql.com/downloads/ 1.找到MySQL Community Edition (GPL) (注:GPL版本为开源,非 ...

  2. Final Cut Pro X 10.4.7 修改长宽比, 截取某一段视频导出

    新建项目时设置过长宽比例,现在要修改 窗口 - 项目属性 - 修改 - 自定义 要注意的是,导出时也要选择一下比例 截取某一段视频导出 将鼠标移到你要截取的片段的开始处,点击快捷键 i(标记-设定范围 ...

  3. vue + WangEnduit

    components 注册组件 <template lang="html"> <div class="editor"> <div ...

  4. Linux--MySQL 日志管理、备份与恢复

    MySQL 日志管理.备份与恢复一.MySQL 日志管理二.数据库备份的重要性与分类  1.数据备份的重要性  2.从物理与逻辑的角度,备份分为  3.从数据库的备份策略角度,备份可分为三.常见的备份 ...

  5. 20210712考试-2021noip11

    这篇总结比我写的好多了建议直接去看 T1 简单的序列 考场:愣了一会,想到以最大值分治.每次枚举最大值两侧更小的区间,st表预处理前缀和和最大值,用桶统计答案. 注意分治时要去掉最大值. const ...

  6. AspectJ——AOP框架快速入门

    一.导包 二.bean.xml配置 三.环绕通知 四,表达式

  7. NPOI相关资料

    http://blog.csdn.net/heyangyi_19940703/article/details/52292755 http://www.cnblogs.com/zhengjuzhuan/ ...

  8. 注释swap分区

    grep  "#" fstab |grep "swap" >/dev/null || sed -i 's/^.*swap/#&/g' fstab

  9. list使用详解

    List双向链表 再谈链表 List链表的概念再度出现了,作为线性表的一员,C++的STL提供了快速进行构建的方法,为此,在前文的基础上通过STL进行直接使用,这对于程序设计中快速构建原型是相当有必要 ...

  10. 使用Java操作Excel表格

    目录 一.配置第三方库 二.使用Apache POI API 1. 打开Excel文件 2. 选择对应的sheet 3. Sheet接口的基本使用 3.1 获取开头行和结束行 3.2 获取Row对象 ...