CF1677E Tokitsukaze and Beautiful Subsegments

因为这是一个排列,所以总共只有 \(O(n\log n)\)\((p,i,j)\),不妨令 \(i<j\)。一个区间 \([l,r]\) 合法,需要存在一个三元组 \((p,i,j)\) 满足 \(l_p<l\le i\)\(j\le r<r_p\)。其中 \(l_p\)\(r_p\) 分别为 \(p\) 左右第一个 \(>a_p\) 的位置。

把上面对 \(l,r\) 的限制看成若干个矩形,但是这样刻画出的区间是若干个矩形的并,不好处理。

注意到一个性质,对于不同的 \(p\),其矩形是不交的。这个其实比较显然,因为 \(p\) 不同就是区间的最大值不同,显然两个矩形就不会有交。

于是我们只要把单个 \(p\) 内部的所有矩形拆成不交的就好了。考虑先删掉被偏序的限制,留下的 \((i,j)\) 满足 \(i\)\(j\) 分别递增。假设现在的限制是 \((i_1,j_1),(i_2,j_2),\cdots,(i_k,j_k)\),那么可以拆成矩形 \(l\in(i_{k-1},i_k],r\in[j_k,r_p)\),其中 \(i_0=l_p\)

于是现在矩形就不交了,容易扫描线维护历史和做到 \(O(n\log n)\)

#include <bits/stdc++.h>
#define ALL(x) begin(x), end(x)
using namespace std;
void file() {
  freopen("1.in", "r", stdin);
  freopen("1.out", "w", stdout);
}
using ll = long long;
using pii = pair<int, int> ;

const int kN = 2e5 + 5, kS = 8e5 + 5, kQ = 1e6 + 5;
int n, q;
array<int, kN> p, rev, l, r;
struct Seg {
  int l, r;
  Seg(int _l, int _r) { l = _l, r = _r; }
};
array<vector<Seg>, kN> seg;
struct Node {
  int l, r, v;
  Node(int _l, int _r, int _v) { l = _l, r = _r, v = _v; }
};
array<vector<Node>, kN> vec;
array<vector<pii>, kN> qry;
array<ll, kQ> ans;

struct Info {
  ll len, sum, sumh;
  Info() { len = sum = sumh = 0; }
  Info(ll _l, ll _s, ll _sh) { len = _l, sum = _s, sumh = _sh; }
};
struct Tag {
  ll t1, t2, t3;
  Tag() { t1 = t2 = t3 = 0; }
  Tag(ll _t1, ll _t2, ll _t3) { t1 = _t1, t2 = _t2, t3 = _t3; }
  bool Empty() { return !t1 && !t2 && !t3; }
};
Info operator + (Info x, Info y) {
  return Info(x.len + y.len, x.sum + y.sum, x.sumh + y.sumh);
}
Info& operator += (Info &x, Tag y) {
  return x = Info(x.len, x.sum + x.len * y.t1, x.sumh + x.sum * y.t2 + x.len * y.t3);
}
Tag& operator += (Tag &x, Tag y) {
  return x = Tag(x.t1 + y.t1, x.t2 + y.t2, x.t1 * y.t2 + x.t3 + y.t3);
}

#define ls (o << 1)
#define rs (o << 1 | 1)
struct SGT {
  array<Info, kS> info;
  array<Tag, kS> tag;
  void Up(int o) { info[o] = info[ls] + info[rs]; }
  void AddT(int o, Tag t) { info[o] += t, tag[o] += t; }
  void Dn(int o) { Tag &t = tag[o]; if(!t.Empty()) AddT(ls, t), AddT(rs, t), t = Tag(); }
  void Build(int o, int l, int r) {
    info[o].len = r - l + 1;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    Build(ls, l, mid), Build(rs, mid + 1, r);
  }
  void Update(int o, int l, int r, int x, int y, int v) {
    if((l > y) || (r < x)) return ;
    if((l >= x) && (r <= y)) return AddT(o, Tag(v, 0, 0));
    int mid = (l + r) >> 1; Dn(o);
    Update(ls, l, mid, x, y, v);
    Update(rs, mid + 1, r, x, y, v);
    Up(o);
  }
  ll Query(int o, int l, int r, int x, int y) {
    if((l > y) || (r < x)) return 0;
    if((l >= x) && (r <= y)) return info[o].sumh;
    int mid = (l + r) >> 1; Dn(o);
    return Query(ls, l, mid, x, y) + Query(rs, mid + 1, r, x, y);
  }
}sgt;

void Push(int l1, int l2, int r1, int r2) {
  vec[r1].emplace_back(l1, l2, 1);
  vec[r2 + 1].emplace_back(l1, l2, -1);
}

void Build() {
  stack<int> stk;
  for(int i = 1; i <= n; stk.push(i++)) {
    for(int top; stk.size(); ) {
      top = stk.top();
      if(p[i] > p[top]) r[top] = i - 1, stk.pop();
      else break;
    }
  }
  while(stk.size()) r[stk.top()] = n, stk.pop();
  for(int i = n; i; stk.push(i--)) {
    for(int top; stk.size(); ) {
      top = stk.top();
      if(p[i] > p[top]) l[top] = i + 1, stk.pop();
      else break;
    }
  }
  while(stk.size()) l[stk.top()] = 1, stk.pop();
  for(int i = 1; i * i <= n; i++) {
    for(int j = i + 1; i * j <= n; j++) {
      int x = rev[i], y = rev[j], pos = rev[i * j];
      if(x > y) swap(x, y);
      if((l[pos] <= x) && (r[pos] >= y)) {
        seg[pos].emplace_back(min(pos, x), max(pos, y));
      }
    }
  }
  for(int i = 1; i <= n; i++) {
    vector<Seg> tmp;
    tmp.swap(seg[i]);
    sort(ALL(tmp), [&](Seg x, Seg y) { return (x.l != y.l) ? (x.l < y.l) : (x.r > y.r); });
    for(Seg k : tmp) {
      while(seg[i].size() && (seg[i].back().r >= k.r)) seg[i].pop_back();
      seg[i].push_back(k);
    }
    if(seg[i].empty()) continue;
    Push(l[i], seg[i][0].l, seg[i][0].r, r[i]);
    for(int j = 1; j < seg[i].size(); j++) {
      Push(seg[i][j - 1].l + 1, seg[i][j].l, seg[i][j].r, r[i]);
    }
  }
}

int main() {
  file();
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n >> q;
  for(int i = 1; i <= n; i++) cin >> p[i], rev[p[i]] = i;
  Build();
  for(int i = 1; i <= q; i++) {
    int l, r;
    cin >> l >> r;
    qry[r].emplace_back(l, i);
  }
  sgt.Build(1, 1, n);
  for(int i = 1; i <= n; i++) {
    for(Node k : vec[i]) sgt.Update(1, 1, n, k.l, k.r, k.v);
    sgt.AddT(1, Tag(0, 1, 0));
    for(pii k : qry[i]) ans[k.second] = sgt.Query(1, 1, n, k.first, i);
  }
  for(int i = 1; i <= q; i++) cout << ans[i] << "\n";
  return 0;
}
posted @ 2025-03-20 20:50  CJzdc  阅读(22)  评论(0)    收藏  举报