P4755 Beautiful Pair
使用笛卡尔树+树上启发式合并解决。
首先建笛卡尔树,然后按照树上启发式合并的一般套路,先枚举轻子树中的每个点,我们设此时根的值为
最后不要忘记把轻子树和本身的贡献加入进去。
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 1e5 + 5, M = 1e9;
using ll = long long;
int n, l[N], r[N], s[N], sz[N], dfn[N], t[N], idx, son[N], top;
ll a[N], ans;
int rt;
vector<ll> p, w;
struct SegT {
int t[N << 5], ls[N << 5], rs[N << 5], idx;
void mod(int &u, int L, int R, int p, int x) {
if (!u)
u = ++idx;
if (L == R)
return t[u] += x, void();
int mid = (L + R) / 2;
if (p <= mid)
mod(ls[u], L, mid, p, x);
else
mod(rs[u], mid + 1, R, p, x);
t[u] = t[ls[u]] + t[rs[u]];
}
int query(int u, int L, int R, int l, int r) {
if (!u)
return 0;
if (l <= L && R <= r)
return t[u];
int mid = (L + R) / 2, ret = 0;
if (l <= mid)
ret += query(ls[u], L, mid, l, r);
if (r > mid)
ret += query(rs[u], mid + 1, R, l, r);
return ret;
}
} T;
void dfs1(int u) {
if (!u)
return;
dfn[u] = ++idx;
t[idx] = u;
sz[u] = 1;
dfs1(l[u]), dfs1(r[u]);
sz[u] += sz[l[u]] + sz[r[u]];
son[u] = (sz[l[u]] > sz[r[u]] ? l[u] : r[u]);
}
void clear(int u) {
for (int i = dfn[u]; i < dfn[u] + sz[u]; i++)
T.mod(rt, 1, M, a[t[i]], -1);
}
void dfs2(int u) {
if (!u)
return;
int hs = son[u], ls = l[u] ^ r[u] ^ son[u];
dfs2(ls), clear(ls);
dfs2(hs);
for (int i = dfn[ls]; i < dfn[ls] + sz[ls]; i++) {
int v = a[t[i]];
ans += T.query(rt, 1, M, 1, a[u] / v);
}
for (int i = dfn[ls]; i < dfn[ls] + sz[ls]; i++)
T.mod(rt, 1, M, a[t[i]], 1);
T.mod(rt, 1, M, a[u], 1);
ans += T.query(rt, 1, M, 1, 1);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(nullptr);
cin >> n;
a[0] = 2e9;
for (int i = 1; i <= n; i++) {
cin >> a[i];
while (a[s[top]] < a[i])
l[i] = s[top--];
r[s[top]] = i, s[++top] = i;
}
dfs1(r[0]);
dfs2(r[0]);
cout << ans;
}