[「LGR-049」洛谷7月月赛 D.Beautiful Pair](https://www.luogu.org/problemnew/show/P4755)

题目大意 : 给出长度为 \(n\) 的序列,求满足 \(i \leq j\) 且 $a_i \times a_j \leq \max(a_i..a_j) $ 的点对\((i, j)\)的数量

\(n \leq 10^5 \ 1 \leq a_i \leq 10^9\)

解题思路 :

直接枚举某一端点貌似很难维护极值,不妨对于每一个极值 \(a_k\),求 $ \max(a_i..a_j) \leq a_k$ 且 \(i \leq k \leq j\) 的点对数

考虑一个每一个点能作为\(\max\)统治的区间可以用单调栈求,并构建出笛卡尔树

此时对于每一个 \(a_k\) 答案由两部分产生:

  1. 点对 \((i, j)\) 满足 \(i = k\) 或 $j = k $,这一部分答案比较简单,就是统治区间内 \(1\) 的个数
  2. 点对 \((i, j)\) 满足 \(i \neq k\) 且 \(j \neq k\) ,此时答案等价于点 \(k\) 在笛卡尔树上的节点的左右子树中各取一个组成合法点对的方案数

第一种情况可以直接前缀和计算,在此不多做讨论,主要看第二种情况

由于是树上的子树问题,我们很容易想到用 \(dsu \ on\ tree\) 的做法来解决

不了解 \(dsu \ on \ tree\) 的可以戳这里的链接

枚举子树大小较小的子树,用树状数组维护较大的子树产生的贡献

对于较小子树中的点 \(u\) ,能与其组成合法点对的点 \(x\) 要满足 \(\frac{maxval}{a_u} \leq a_x\),直接用树状数组统计前缀和即可

/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int f = 0, ch = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
#define N (500005)
#define int ll
int a[N], b[N], n, ans;
namespace Ls{
int s[N]; int lens = 0;
inline int calc(int x){
int res = upper_bound(s + 1, s + lens + 1, x) - s - 1;
return res;
}
inline void Realmain(){
for(int i = 1; i <= n; i++) s[i] = a[i];
sort(s + 1, s + n + 1);
lens = unique(s + 1, s + n + 1) - s - 1;
}
}
struct Fenwick{
int s[N];
inline int lowbit(int x){ return x & -x; }
inline void add(int x, int v){
for(int i = x; i <= n; i += lowbit(i)) s[i] += v;
}
inline int query(int x){
int ans = 0;
for(int i = x; i; i -= lowbit(i)) ans += s[i];
return ans;
}
}Bit;
namespace Treap{
int sz[N], ch[N][2], s[N], l[N], r[N], st[N], top;
inline void Getsize(int u){
sz[u] = 1;
int ls = ch[u][0], rs = ch[u][1];
if(ls) Getsize(ls), sz[u] += sz[ls];
if(rs) Getsize(rs), sz[u] += sz[rs];
if(!u) sz[u] = 0;
}
inline void Add(int u){
Bit.add(b[u], 1);
if(ch[u][0]) Add(ch[u][0]);
if(ch[u][1]) Add(ch[u][1]);
}
inline void Clear(int u){
Bit.add(b[u], -1);
if(ch[u][0]) Clear(ch[u][0]);
if(ch[u][1]) Clear(ch[u][1]);
}
inline int Count(int u, int val){
int pos = Ls::calc(val / a[u]);
int res = Bit.query(pos);
if(ch[u][0]) res += Count(ch[u][0], val);
if(ch[u][1]) res += Count(ch[u][1], val);
return res;
}
inline void solve(int u){
int p = sz[ch[u][0]] > sz[ch[u][1]] ? 0 : 1;
int ms = ch[u][p], ls = ch[u][p^1];
if(ls) solve(ls), Clear(ls);
if(ms) solve(ms);
if(ls) ans += Count(ls, a[u]);
if(u){ if(ls) Add(ls); Bit.add(b[u], 1); }
}
inline void Build(){
for(int i = 1; i <= n; i++){
while(a[st[top]] <= a[i] && top) r[st[top--]] = i - 1;
int f = st[top]; l[i] = f + 1;
ch[i][0] = ch[f][1], ch[f][1] = i, st[++top] = i;
}
for(int i = 1; i <= n; i++) if(!r[i]) r[i] = n;
}
inline void Realmain(){
Build(), Getsize(0), solve(0);
for(int i = 1; i <= n; i++) s[i] = s[i-1] + (a[i] == 1 ? 1 : 0);
for(int i = 1; i <= n; i++) ans += s[r[i]] - s[l[i]-1];
cout << ans << endl;
}
}
main(){
read(n);
for(int i = 1; i <= n; i++) read(a[i]);
Ls::Realmain();
for(int i = 1; i <= n; i++) b[i] = Ls::calc(a[i]);
Treap::Realmain();
return 0;
}

「LGR-049」洛谷7月月赛 D.Beautiful Pair的更多相关文章

  1. 「P4994」「洛谷11月月赛」 终于结束的起点(枚举

    题目背景 终于结束的起点终于写下句点终于我们告别终于我们又回到原点…… 一个个 OIer 的竞赛生涯总是从一场 NOIp 开始,大多也在一场 NOIp 中结束,好似一次次轮回在不断上演.如果这次 NO ...

  2. 「P4996」「洛谷11月月赛」 咕咕咕(数论

    题目描述 小 F 是一个能鸽善鹉的同学,他经常把事情拖到最后一天才去做,导致他的某些日子总是非常匆忙. 比如,时间回溯到了 2018 年 11 月 3 日.小 F 望着自己的任务清单: 看 iG 夺冠 ...

  3. 「LuoguP4995」「洛谷11月月赛」 跳跳!(贪心

    题目描述 你是一只小跳蛙,你特别擅长在各种地方跳来跳去. 这一天,你和朋友小 F 一起出去玩耍的时候,遇到了一堆高矮不同的石头,其中第 ii 块的石头高度为 h_ihi​,地面的高度是 h_0 = 0 ...

  4. 「线段树」「单点修改」洛谷P1198 [JSOI2008]最大数

    「线段树」「单点修改」洛谷P1198 [JSOI2008]最大数 题面描述 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数, ...

  5. 洛谷4月月赛R2

    洛谷4月月赛R2 打酱油... A.koishi的数学题  线性筛约数和就可以\(O(N)\)了... #include <iostream> #include <cstdio> ...

  6. 洛谷3月月赛 R1 Step! ZERO to ONE

    洛谷3月月赛 R1 Step! ZERO to ONE 普及组难度 290.25/310滚粗 t1 10分的日语翻译题....太难了不会... t2 真·普及组.略 注意长为1的情况 #include ...

  7. 【洛谷5月月赛】玩游戏(NTT,生成函数)

    [洛谷5月月赛]玩游戏(NTT,生成函数) 题面 Luogu 题解 看一下要求的是什么东西 \((a_x+b_y)^i\)的期望.期望显然是所有答案和的平均数. 所以求出所有的答案就在乘一个逆元就好了 ...

  8. 【LGR-054】洛谷10月月赛II

    [LGR-054]洛谷10月月赛II luogu 成功咕掉Codeforces Round #517的后果就是,我\(\mbox{T4}\)依旧没有写出来.\(\mbox{GG}\) . 浏览器 \( ...

  9. 【LGR-051】洛谷9月月赛

    [LGR-051]洛谷9月月赛 luogu 签到题 description 给出\(K\)和质数\(m\),求最小的\(N\)使得\(111....1\)(\(N\)个\(1\))\(\equiv k ...

随机推荐

  1. 「6月雅礼集训 2017 Day8」infection

    [题目大意] 有$n$个人,每个人有一个初始位置$x_i$和一个速度$v_i$,你需要选择若干个人来感染一个傻逼病毒. 当两个人相遇(可以是正面和背面),傻逼病毒会传染,求经过无限大时间后,传染完所有 ...

  2. java map转json servlet response

    1.手写一个map转json的类 1.1 调用方式 //给前端放回json数据 Map<String, Object> map = new HashMap<>(); map.p ...

  3. bufferd对象详解

    使用buffer类处理二进制数据 在客户端javascript脚本代码中,对于二进制数据并没有提供一个很好的支持.然后在nodejs中需要处理像TCP流或文件流时,必须要处理二进制数据.因此在node ...

  4. canvas_基于canvan绘制的双半圆环进度条

    效果图 实现原理: 1.使用canvas绘制两个半圆弧,底图灰色半圆弧和颜色进度圆弧. 2.利用setInterval计时器,逐步改变颜色进度条,达到进度条的效果. 效果代码: <!DOCTYP ...

  5. Python模块学习 - Argparse

    argparse模块 在Python中,argparse模块是标准库中用来解析命令行参数的模块,用来替代已经过时的optparse模块.argparse模块能够根据程序中的定义从sys.argv中解析 ...

  6. 使用makecontext实现用户线程【转】

    转自:http://blog.csdn.net/cyberlabs/article/details/6920138 使用makecontext实现用户线程 现代Unix系统都在ucontext.h中提 ...

  7. python基础===python os.path模块

    os.path.abspath(path) #返回绝对路径 os.path.basename(path) #返回文件名 os.path.commonprefix(list) #返回list(多个路径) ...

  8. 查看及连接指定 docker container

    环境: 1.centos7 2.以root身份登录 3.已安装docker并且运行着一个container A.查看正在运行的container docker ps 效果: B.查看本地所有conta ...

  9. 面试题之实现系统函数系列一:实现memmove函数

    编译环境 本系列文章所提供的算法均在以下环境下编译通过. [算法编译环境]Federa 8,linux 2.6.35.6-45.fc14.i686 [处理器] Intel(R) Core(TM)2 Q ...

  10. 883H - Palindromic Cut(思维+STL)

    题目链接:http://codeforces.com/problemset/problem/883/H 题目大意:给一段长度为n的字符串s,想让你把s切成几段长度相同的回文串,可以改变s中字符的排列, ...