题目传送门

题目大意

给出一个 \(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. 配置双jdk

    1 CLASSPATH:.%JAVA_HOME%\lib;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar 2 JAVA_HOME:%JAVA_HOME ...

  2. Install Docker Engine on CentOS 在CentOS 7 上安装Docker

    Install Docker Engine on CentOS OS Requirements 系统要求 To install Docker Engine,you need a maintained ...

  3. client-go实战之五:DiscoveryClient

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  4. [Elasticsearch] ES更新问题踩坑记录

    问题描述 我们有个系统设计的时候针对Hive创建表.删除表, 需要更新ES中的一个状态,标记是否删除,在几乎同时执行两条下面的语句的时候,发现在ES 中出现表即使被创建了还是无法被查询到的情况,针对该 ...

  5. linux下制作img文件

    一.简介 制作img文件可以使用linux系统中的dd命令制作,Linux dd 命令用于读取.转换并输出数据.dd 可从标准输入或文件中读取数据,根据指定的格式来转换数据,再输出到文件.设备或标准输 ...

  6. TypeScript 中装饰器的理解?应用场景?

    一.是什么 装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上 是一种在不改变原类和使用继承的情况下,动态地扩展对象功能 同样的,本质也不是什么高大上的结构,就是一个普通的 ...

  7. JetBrains 系列软件汉化包 2017.3-2018.1

    JetBrains 系列软件汉化包 关键字: Android Studio 3.0-3.1.3 汉化包 CLion 2018.1-2018.2 汉化包 GoLand 2017.3.2-2018.2 汉 ...

  8. 变着花样来接参,PHP中接收外部参数的方式

    对于PHP这样一个web语言来说,接参是非常重要的一个能力.毕竟从前端表单或异步请求传递上来的数据都要获取到才能进行正常的交互展示.当然,这也是所有能够进行web开发的语言的必备能力.今天我们就来看看 ...

  9. 使用ELK监控Nginx日志实现接口流量访问统计

    前段时间自己看书学习了一下elasticSearch,后面自己实践了使用elasticSearch.logStash.kibana搭建一个网站接口流量访问统计的监控看板.在这里做一些记录学习. 先看一 ...

  10. Docker DevOps实战:Docker+Jenkins+Python+Pytest+Allure(2)- Jenkins初始化、Jenkins插件、Jenkins配置、自动化测试

    Jenkins初始化 step-1 访问Jenkins http://ip:80  step-2 查看密码.输入密码 # 方式一:通过查看容器日志 [root@localhost ~]# docker ...