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;
}
浙公网安备 33010602011771号