题目传送门

题目大意

给出一个 \(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. go测试--进阶

    目录 前言 控制编译的参数 -args -json -o 控制测试的参数 -bench regexp -benchtime s -cpu 1,2,4 -count n -failfast -list ...

  2. Spring 事务回滚机制详解

    1:事务原理 1.2:aop/动态代理 类路径:org/springframework/aop/framework/CglibAopProxy.java ReflectiveMethodInvocat ...

  3. 基于Linux系统的网络服务——高速缓存DNS及企业级域名解析服务

    1.DNS域名系统 DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数 ...

  4. JS_DOM操作之操作标签

    <标签名 属性1="属性值1" 属性2="属性值2"-->文本</标签名> 1 - 文本操作 <div class="c ...

  5. Python__Xpath模块

    import requests from lxml import etree # 导入xpath headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 6 ...

  6. ABP VNext发布遇到的坑

    本地调试没有问题,发布后通过Token调用其他API时,出现返回JSON中提示:Authorization failed! Given policy has not granted. 需要修改apps ...

  7. Mybatis公司开发常用!

    Mybatis核心 本文重点:注解开发,mybatis多表操作,动态SQL(WHERE,SET,IF,SQL-ID减少复用) 代码地址--https://gitee.com/zhangjzm/my-b ...

  8. Lombok中@Data注解的坑

    开发遇到@Data注解的大坑 如果使用@Data注解,会默认重写hashcode和equals方法 那会遇到什么问题呢? 比如说: @Data public class DataTest { priv ...

  9. 机器学习——EM算法

    1 数学基础 在实际中,最小化的函数有几个极值,所以最优化算法得出的极值不确实是否为全局的极值,对于一些特殊的函数,凸函数与凹函数,任何局部极值也是全局极致,因此如果目标函数是凸的或凹的,那么优化算法 ...

  10. CodeForce-799C Fountains (记忆化DP)

    Fountains CodeForces - 799C 某土豪想要造两座喷泉.现在有 n 个造喷泉的方案,我们已知每个方案的价格以及美观度.有两种合法的货币:金币和钻石.这两种货币之间不能以任何方式转 ...