#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, Q, a[200001], ans[200001], rem[200001];
map<int, vector<int>> pos;
struct Query {
int l, r, x, id;
} q[200001];
map<int, vector<Query>> qs;
struct Info {
int tot, lh, rh; // 最左边有没有块,最右边有没有块
};
Info add(const Info a, const Info b) { // 注意该运算不满足交换律
if (a.tot + a.lh + a.rh == -3) return b;
if (b.tot + b.lh + b.rh == -3) return a;
return {a.tot + b.tot - (a.rh && b.lh), a.lh, b.rh};
}
namespace SGT {
Info res[2000003];
#define ls(i) (i << 1)
#define rs(i) (i << 1 | 1)
void build(int i, int l, int r) {
if (l == r) return res[i] = {1, 1, 1}, void();
int mid = (l + r) / 2; build(ls(i), l, mid); build(rs(i), mid + 1, r);
res[i] = add(res[ls(i)], res[rs(i)]);
}
void update(int i, int l, int r, int qp) {
if (l > qp || r < qp) return; int mid = (l + r) / 2;
if (l == r && l == qp) return res[i] = {0, 0, 0}, void();
update(ls(i), l, mid, qp); update(rs(i), mid + 1, r, qp);
res[i] = add(res[ls(i)], res[rs(i)]);
}
Info query(int i, int l, int r, int ql, int qr) {
if (l > qr || r < ql) return {-1, -1, -1};
//printf("%d %d %d %d %d\n", l, r, res[i].tot, res[i].lh, res[i].rh);
if (l >= ql && r <= qr) return res[i];
int mid = (l + r) / 2;
return add(query(ls(i), l, mid ,ql, qr), query(rs(i), mid + 1, r, ql, qr));
}
}
signed main() {
scanf("%lld%lld", &n, &Q);
vector<int> qss;
for (int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
pos[a[i]].push_back(i);
qss.push_back(a[i]);
}
sort(qss.begin(), qss.end());
auto enit = unique(qss.begin(), qss.end());
int minv = 1ll << 60;
for (int i = 1; i <= Q; ++i) {
scanf("%lld%lld%lld", &q[i].l, &q[i].r, &q[i].x);
if (q[i].x < qss[0]) q[i].x = -1;
else q[i].x = qss[min((std::vector<long long>::size_type)(lower_bound(qss.begin(), enit, q[i].x + 1) - qss.begin() - 1), qss.size() - 1)];
q[i].id = i; qs[q[i].x].push_back(q[i]);
minv = min(minv, q[i].x);
}
for (int i = 1; i <= n; ++i) {
if (a[i] < minv) pos[minv].push_back(i);
}
SGT::build(1, 1, n);
for (auto i : qs) {
for (auto j : pos[i.first]) {
if (rem[j]) continue;
rem[j] = 1;
SGT::update(1, 1, n, j);
}
for (auto j : i.second) {
Info tmp = SGT::query(1, 1, n, j.l, j.r);
ans[j.id] = tmp.tot;
//printf("ans: %lld, %lld, %lld, %lld\n", j.id, tmp.tot, tmp.lh, tmp.rh);
}
}
for (int i = 1; i <= Q; ++i) printf("%lld\n", ans[i]);
}
大体思路:
线段树记录的节点表示目前的岛屿组成极大未淹没连续子段的情况,tot 表示总数,lh 表示这个区间最左边的岛屿是否被淹没,rh 表示这个区间最右边的岛屿是否被淹没。
严重怀疑是第一步写错了,或者是线段树 query 返回 {-1, -1, -1} 这个地方。