分治 + 主席树。

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

注意,这时候左半边是$[l, mid]$,而右区间是$[mid, r]$,我们在这个区间处理的时候要算完所有$mid$的情况,然后我们每一次分治的时候去处理$solve(l, mid - 1)$和$solve(mid + 1, r)$,要不然当$mid$是端点的时候就会无限递归下去。

问题转化快速算出一个区间内$\leq$一个数的数,只要一棵主席树就可以解决了,区间最大值可以用$ST$表维护出来。

我们每一次选取一个比较短的区间去枚举然后算另一个区间的答案,这样子每一次计算区间的长度至少减少一半,这样子可以保证时间复杂度。

时间复杂度$O(nlog^2n)$。

Code:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll; const int N = 1e5 + ;
const int Lg = ;
const ll inf = 1LL << ; int n, tot = ;
ll ans = 0LL, a[N], num[N]; template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} template <typename T>
inline void chkMax(T &x, T y) {
if(y > x) x = y;
} namespace ST {
int st[N][Lg], len[N]; inline int bet(int x, int y) {
return a[x] > a[y] ? x : y;
} inline void prework() {
for(int j = ; j <= ; j++)
for(int i = ; i + ( << j) - <= n; i++)
st[i][j] = bet(st[i][j - ], st[i + ( << (j - ))][j - ]);
} inline int qMax(int x, int y) {
int k = len[y - x + ];
return bet(st[x][k], st[y - ( << k) + ][k]);
} } using namespace ST; namespace SegT {
struct Node {
int lc, rc;
ll sum;
} s[N * ]; int root[N], nodeCnt = ; #define lc(p) s[p].lc
#define rc(p) s[p].rc
#define sum(p) s[p].sum
#define mid ((l + r) >> 1) void ins(int &p, int l, int r, int x, int pre) {
s[p = ++nodeCnt] = s[pre];
++sum(p);
if(l == r) return; if(x <= mid) ins(lc(p), l, mid, x, lc(pre));
else ins(rc(p), mid + , r, x, rc(pre));
} ll query(int r1, int r2, int l, int r, int x, int y) {
if(x > y) return 0LL;
if(x <= l && y >= r) return sum(r2) - sum(r1); ll res = 0LL;
if(x <= mid) res += query(lc(r1), lc(r2), l, mid, x, y);
if(y > mid) res += query(rc(r1), rc(r2), mid + , r, x, y);
return res;
} #undef mid } using namespace SegT; void solve(int l, int r) {
if(l > r) return; int mid = qMax(l, r);
if(mid - l < r - mid) {
for(int i = l; i <= mid; i++) {
int pos = upper_bound(num + , num + + tot, (ll) (num[a[mid]] / num[a[i]])) - num - ;
ans += query(root[mid - ], root[r], , tot, , pos);
}
} else {
for(int i = mid; i <= r; i++) {
int pos = upper_bound(num + , num + + tot, (ll) (num[a[mid]] / num[a[i]])) - num - ;
ans += query(root[l - ], root[mid], , tot, , pos);
}
} solve(l, mid - ), solve(mid + , r);
} int main() {
read(n);
for(int i = ; i <= n; i++) {
read(a[i]);
len[i] = log2(i), st[i][] = i;
num[++tot] = a[i];
}
prework(); num[++tot] = inf;
sort(num + , num + + tot);
tot = unique(num + , num + tot + ) - num - ; for(int i = ; i <= n; i++) {
a[i] = lower_bound(num + , num + + tot, a[i]) - num;
ins(root[i], , tot, a[i], root[i - ]);
} /* for(int i = 1; i <= n; i++)
printf("%lld ", a[i]);
printf("\n"); */ solve(, n); printf("%lld\n", ans);
return ;
}

最新文章

  1. KMP算法的详细解释及实现
  2. 简单回忆一下JavaScript中的数据类型
  3. ubuntu12.04 安装配置jdk1.7
  4. INERT DELEYED、INSERT IGNORE replace into和insert区别
  5. camera理论基础和工作原理
  6. NSNotificationCenter基础知识
  7. 解决SQL订阅过程中找不到已经创建的订阅
  8. Linux下非root用户安装软件的一般流程:
  9. thinkphp实现文件的下载
  10. 在CentOS上安装owncloud企业私有云过程
  11. Python-Django-BMS-增删改查
  12. JMeter—监听器(十二)
  13. spring事务中出现oracle游标溢出的解决方案
  14. [转]MySQL中乐观锁、悲观锁(共享锁、排他锁)简介
  15. Flutter实例一--底部规则导航栏制作
  16. Ubuntu系统下使用Jenkins进行项目的自动构建还是项目回滚方法
  17. 解决 login.live.com onedrive.live.com 等微软国外网站打不开问题
  18. [翻译] LLSimpleCamera
  19. antd 父组件获取子组件中form表单的值
  20. OpenGL核心之SSAO技术解说(一)

热门文章

  1. Windows下安装pillow、opencv库问题,亲测可行
  2. 在JVM中,新生代和旧生代有何区别?GC的回收方式有几种?server和client有和区别?
  3. Windows 系统定时自动重启
  4. PowerDesigner导出word表结构
  5. 完整的CRUD——javaweb
  6. 第12篇 PSR-1规范
  7. 支付宝sdk集成
  8. 善待Erlang 代码 -- 巧用 user_default
  9. Docker Toolbox on Windows 7
  10. Couldn&#39;t find a tree builder with the features you requested: lxml. Do you need to install a parser library?