洛谷P4755 Beautiful Pair 题解 笛卡尔树+启发式合并+线段树合并
题目链接:https://www.luogu.com.cn/problem/P4755
解题思路:参考自 Find_NICK大佬的博客。
示例程序:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 1e5 + 5, inf = 1e9, maxm = maxn * 50;
struct Segt {
int tr[maxm], ls[maxm], rs[maxm], idx;
void push_up(int u) {
tr[u] = tr[ ls[u] ] + tr[ rs[u] ];
}
void add(int p, int v, int l, int r, int &u) {
if (!u) u = ++idx;
if (l == r) {
tr[u] += v;
return;
}
int mid = (l + r) >> 1;
(p <= mid) ? add(p, v, l, mid, ls[u]) : add(p, v, mid+1, r, rs[u]);
push_up(u);
}
int Merge(int u, int v, int l, int r) {
if (!u || !v) return u + v;
tr[u] += tr[v];
if (l == r)
return u;
int mid = (l + r) >> 1;
ls[u] = Merge(ls[u], ls[v], l, mid);
rs[u] = Merge(rs[u], rs[v], mid+1, r);
return u;
}
int query(int L, int R, int l, int r, int u) {
if (!u) return 0;
if (L <= l && r <= R)
return tr[u];
int res = 0, mid = (l + r) >> 1;
if (L <= mid) res += query(L, R, l, mid, ls[u]);
if (R > mid) res += query(L, R, mid+1, r, rs[u]);
return res;
}
} segt;
int n, a[maxn], root[maxn], ls[maxn], rs[maxn], rt;
ll ans;
void di_ka_er() {
stack<int> stk;
for (int i = 1; i <= n; i++) {
int last = 0;
while (!stk.empty() && a[stk.top()] < a[i]) {
last = stk.top();
stk.pop();
}
if (!stk.empty()) rs[stk.top()] = i;
else rt = i;
ls[i] = last;
stk.push(i);
}
}
void dfs(int u, int l, int r) {
if (!u)
return;
dfs(ls[u], l, u-1);
dfs(rs[u], u+1, r);
if (u - l < r - u) {
root[u] = root[ rs[u] ];
segt.add(a[u], 1, 1, inf, root[u]);
for (int i = l; i <= u; i++) {
ans += segt.query(1, a[u]/a[i], 1, inf, root[u]);
}
segt.Merge(root[u], root[ ls[u] ], 1, inf);
}
else {
root[u] = root[ ls[u] ];
segt.add(a[u], 1, 1, inf, root[u]);
for (int i = u; i <= r; i++) {
ans += segt.query(1, a[u]/a[i], 1, inf, root[u]);
}
segt.Merge(root[u], root[ rs[u] ], 1, inf);
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", a+i);
di_ka_er();
dfs(rt, 1, n);
printf("%lld\n", ans);
return 0;
}
浙公网安备 33010602011771号