[Codeforces1117G]Recursive Queries

给定长度为 (n),的排列 (p_1, p_2, dots, p_n)(q) 次询问,每次询问一段区间 (l, r),计算

[f(l, r) = egin{cases} (r - l + 1) + f(l, m_{l, r} - 1) + f(m_{l, r} + 1, r) & l leq r\ 0 & l > r end{cases} ]

其中 (m_{l, r}) 表示 (p_l, p_{l + 1}, dots, p_r) 中最大值的下标。

(n, q leq 10^6)

容易发现 (f(l, r)) 是区间 ([l, r]) 笛卡尔树的节点 (size) 和。

一个点 (p_i) 的在笛卡尔树上的子树为一个区间 ([lg_i + 1, rg_i - 1]),即左右两边离他最近的比他大的两个数之间。

所以

[f(l, r) = sum_{i = l}^r (min{r, rg_i - 1} - max{l, lg_i + 1} + 1) ]

先用单调栈预处理出 (lg_i, rg_i),区间加一 ([lg_i, rg_i]),区间求和 ([l, r]),这个可以用差分线性求出,但是多出来区间 ([l, r]) 之外的贡献。

正序扫一遍去掉 ([1, l - 1]) 的贡献,倒序扫一遍去掉 ([r + 1, n]) 的贡献,这个可以用树状数组区间加区间求和来实现。

#include <bits/stdc++.h>
#ifdef LOCAL
#define dbg(args...) std::cerr << "33[32;1m" << #args << " -> ", err(args)
#else
#define dbg(...)
#endif
inline void err() { std::cerr << "33[0m
"; }
template<class T, class... U>
inline void err(const T &x, const U &... a) { std::cerr << x << ' '; err(a...); }
template <class T>
inline void readInt(T &w) {
  char c, p = 0;
  while (!isdigit(c = getchar())) p = c == '-';
  for (w = c & 15; isdigit(c = getchar());) w = w * 10 + (c & 15);
  if (p) w = -w;
}
template <class T, class... U>
inline void readInt(T &w, U &... a) { readInt(w), readInt(a...); }
template <class T, class U>
inline bool smin(T &x, const U &y) { return y < x ? x = y, 1 : 0; }
template <class T, class U>
inline bool smax(T &x, const U &y) { return x < y ? x = y, 1 : 0; }

typedef long long LL;
typedef std::pair<int, int> PII;

constexpr int N(1e6 + 5);
int n, m, a[N], s[N], l[N], r[N];


class FenwickTree {
 public:
  void add(int l, int r) {
    add(v, l, 1), add(v, r + 1, -1);
    add(vi, l, l), add(vi, r + 1, -r - 1);
  }
  LL ask(int l, int r) {
    return ask(v, r) * (r + 1) - ask(v, l - 1) * l - ask(vi, r) + ask(vi, l - 1);
  }
  void clear() {
    memset(v, 0, sizeof v);
    memset(vi, 0, sizeof vi);
  }
 private:
  LL v[N], vi[N];
  void add(LL c[], int p, int x) {
    for (; p <= n; p += p & -p) c[p] += x;
  }
  LL ask(LL c[], int p) {
    LL r = 0;
    for (; p; p -= p & -p) r += c[p];
    return r;
  }
} t;

int ql[N], qr[N];
std::vector<int> lq[N], rq[N];
LL b[N], ans[N];
int main() {
  readInt(n, m);
  for (int i = 1; i <= n; i++) readInt(a[i]);
  for (int i = 1; i <= n; i++) {
    while (s[0] && a[s[s[0]]] < a[i]) s[0]--;
    b[l[i] = s[s[0]] + 1]++;
    // printf("+ %d %d
", s[s[0]], i);
    s[++s[0]] = i;
  }
  s[0] = 0;
  for (int i = n; i; i--) {
    while (s[0] && a[s[s[0]]] < a[i]) s[0]--;
    if (s[0])
      b[r[i] = s[s[0]]]--;
    else 
      r[i] = n + 1;
    // printf("- %d %d
", i, s[s[0]]);
    
    s[++s[0]] = i;
  }
  for (int i = 1; i <= n; i++) b[i] += b[i - 1];
  for (int i = 1; i <= n; i++) b[i] += b[i - 1];
  for (int i = 1; i <= m; i++) readInt(ql[i]), lq[ql[i]].push_back(i);
  for (int i = 1; i <= m; i++) readInt(qr[i]), rq[qr[i]].push_back(i);
  for (int i = 1; i <= n; i++) {
    for (int j : lq[i]) ans[j] -= b[ql[j] - 1] + t.ask(ql[j], qr[j]);
    t.add(l[i], r[i] - 1);
  }
  t.clear();
  for (int i = n; i; i--) {
    for (int j : rq[i]) ans[j] += b[qr[j]] - t.ask(ql[j], qr[j]);
    t.add(l[i], r[i] - 1);
  }
  for (int i = 1; i <= m; i++) printf("%lld ", ans[i]);
  return 0;
}
原文地址:https://www.cnblogs.com/HolyK/p/14162414.html