题解 QOJ2559【Endless Road】/ SS241006D【套路题】
Petrozavodsk Winter 2022. Day 2. KAIST Contest + KOI TST 2021
XXII Open Cup named after E.V. Pankratiev, Grand Prix of Daejeon
题目描述
现在有 \(10^9\) 个花盆,依次编号为 \(1,2,\dots,10^{9}\) 。
给定 \(n\) 个二元组 \(L_i,R_i(L_i<R_i)\) ,我们将进行 \(n\) 次以下操作:
-
设当前第 \(i\) 个二元组的权值是满足花盆 \(x\) 为空且 \(L_i<x\le R_i\) 的 \(x\) 数量。选出未被选过且权值最小的二元组 \(p\) 。如果存在多个权值最小的二元组,选择其中编号最小的。
-
对于 \(L_p<x\le R_p\) ,在花盆 \(x\) 中种上花。
请求出每次操作选择出的二元组 \(p\)。
保证对于 \(1\le i<j\le n,R_i-L_i\le R_j-L_j\) 。
对于所有数据,\(1\le n\le 2.5\times 10^5,0\le L_i<R_i\le 10^{9}\),对于 \(1\le i<j\le n\) ,\(R_i-L_i\le R_j-L_j\) 。
solution
改成左闭右开。离散化。跳过一些暴力后,我们发现:两个互相包含的区间 \(i<j, [L_i, R_i)\subseteq[L_j, R_j)\),无论如何操作,都是 \(i\) 先被栽种,\(j\) 后被栽种。可以对花盆的位置分类,发现 \(i\) 区间的权值总是不大于 \(j\) 的。而如果我们去掉包含其它区间的区间,剩下的都是左、右断点分别单调的区间(称作合法区间),对这些合法区间我们将其存放在线段树上它们各自左端点的位置,然后可以二分、懒标记等一系列操作进行栽种(发现权值减少的合法区间的左端点连续)。
剩下的问题是删除一个合法区间后怎么找到新的合法区间。我们将所有区间按照右端点升序为第一关键字,左端点降序为第二关键字,以及自身编号升序为第三关键字,对所有区间进行排序,使每个区间获得一个排名。这样排序后,两个互相包含的区间 \(i<j, [L_i, R_i)\subseteq[L_j, R_j)\),\(i\) 的排名一定比 \(j\) 小(相当于给这个包含关系的 DAG 找了一个拓扑序)。于是,我们在删除一个合法区间时,先找到小于这个合法区间的左端点的最大的左端点(即其前一个合法区间的左端点,记为 \(t\)),新的区间的左端点起码需要 \(>t\);再找到大于这个合法区间的排名的最小排名(即其后一个合法区间的排名,记为 \(q\)),新的区间的排名若 \(\geq q\) 则它的右端点一定 \(\geq q\) 的右端点,也不合法(取等的情况讨论一下发现也对)。有了这两个限制,我们找到的就都是合法区间。
用另一棵线段树将所有非法区间存放在线段树上它们各自排名的位置,每次删除区间时,记删除的区间的排名为 \(x\),去找排名在 \([x, n]\) 中左端点 \(>t\) 的一个非法区间,若其排名 \(\geq q\) 则结束;否则将其升变为合法区间,并使 \(t\gets\) 其左端点。
至此可以在 \(O(n\log n)\) 的时间复杂度内解决原问题。
code
需要开两棵线段树,支持的线段树二分都有所不同。找 \(t,q\) 可以用一个 std::set
,因为合法区间按照排名、或者左端点、或者右端点排序的结果都是一样的,可以随便写。插入新的合法区间时需要知晓其权值,使用另一个树状数组维护。seg1
是合法区间,seg2
是非法区间。
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) ((void)fprintf(stderr, ##__VA_ARGS__))
#else
#define endl "\n"
#define debug(...) ((void)0)
#endif
using LL = long long;
template <int N, class T>
struct fenwick {/*{{{*/
T c[N + 10];
fenwick() { memset(c, 0, sizeof c); }
void add(int p, T k) { for (; p <= N; p += p & -p) c[p] += k; }
T qry(int p) { T r = 0; for (; p >= 1; p -= p & -p) r += c[p]; return r; }
};/*}}}*/
template <class T>
struct flower {/*{{{*/
vector<T> vec;
template <class U> flower& operator<<(U&& x) {
vec.push_back(forward<U>(x));
return *this;
}
size_t build() {
auto bg = vec.begin(), ed = vec.end();
sort(bg, ed);
vec.erase(unique(bg, ed), ed);
return vec.size();
}
size_t operator()(const T& x) const {
return lower_bound(vec.begin(), vec.end(), x) - vec.begin();
}
T operator[](int i) const { return vec[i]; }
};/*}}}*/
struct range {
int l, r, id;
} a[250010];
int n, m, nxt[500010], wh[500010];
int findnxt(int x) { return nxt[x] == x ? x : nxt[x] = findnxt(nxt[x]); }
flower<int> hua;
fenwick<500010, int> fen;
set<int> st;
namespace seg2 {
constexpr int N = 2.5e5;
int maxl[N << 2];
void maintain(int p) { maxl[p] = max(maxl[p << 1], maxl[p << 1 | 1]); }
void build(int p, int l, int r) {/*{{{*/
if (l == r) {
maxl[p] = -1e9;
return ;
}
int mid = (l + r) >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
maintain(p);
}/*}}}*/
void setValue(int x, int v, int p, int l, int r) {/*{{{*/
if (l == r) {
maxl[p] = v;
return ;
}
int mid = (l + r) >> 1;
if (x <= mid) setValue(x, v, p << 1, l, mid);
else setValue(x, v, p << 1 | 1, mid + 1, r);
maintain(p);
}/*}}}*/
int binary(int L, int R, int v, int p, int l, int r) {
if (L <= l && r <= R) {
if (maxl[p] <= v) return n + 1;
if (l == r) return l;
}
int mid = (l + r) >> 1;
int ret = L <= mid ? binary(L, R, v, p << 1, l, mid) : n + 1;
if (ret <= n) return ret;
return mid < R ? binary(L, R, v, p << 1 | 1, mid + 1, r) : n + 1;
}
void enable(int id) { debug("seg2::enable(%d)\n", a[id].id); setValue(id, a[id].l, 1, 1, n); }
void disable(int id) { debug("seg2::disable(%d)\n", a[id].id); setValue(id, -1e9, 1, 1, n); }
};
namespace seg1 {
constexpr int N = 5e5;
pair<int, int> ans[N << 2];
int tag[N << 2], maxr[N << 2];
void maintain(int p) {
ans[p] = min(ans[p << 1], ans[p << 1 | 1]);
maxr[p] = max(maxr[p << 1], maxr[p << 1 | 1]);
}
void spread(int p, int k) { ans[p].first -= k, tag[p] += k; }
void pushdown(int p) { spread(p << 1, tag[p]), spread(p << 1 | 1, tag[p]), tag[p] = 0; }
void build(int p, int l, int r) {/*{{{*/
tag[p] = 0;
if (l == r) {
ans[p] = make_pair(1e9, -1);
maxr[p] = -1e9;
return ;
}
int mid = (l + r) >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
maintain(p);
}/*}}}*/
void setValue(int x, int id, int p, int l, int r) {/*{{{*/
if (l == r) {
if (id > 0) {
int len = hua[a[id].r - 1] - hua[a[id].l - 1];
int lenp = fen.qry(a[id].r - 1) - fen.qry(a[id].l - 1);
ans[p] = make_pair(len - lenp, a[id].id);
maxr[p] = a[id].r;
} else {
ans[p] = make_pair(1e9, -1);
maxr[p] = -1e9;
}
return ;
}
int mid = (l + r) >> 1;
pushdown(p);
if (x <= mid) setValue(x, id, p << 1, l, mid);
else setValue(x, id, p << 1 | 1, mid + 1, r);
maintain(p);
}/*}}}*/
void modify(int L, int R, int k, int p, int l, int r) {/*{{{*/
if (L <= l && r <= R) return spread(p, k);
int mid = (l + r) >> 1;
pushdown(p);
if (L <= mid) modify(L, R, k, p << 1, l, mid);
if (mid < R) modify(L, R, k, p << 1 | 1, mid + 1, r);
maintain(p);
}/*}}}*/
void enable(int id) {
debug("seg1::enable(%d) = [%d, %d]\n", a[id].id, a[id].l, a[id].r);
st.insert(id);
setValue(a[id].l, id, 1, 1, m);
}
void disable(int id) {
debug("seg1::disable(%d) = [%d, %d]\n", a[id].id, a[id].l, a[id].r);
assert(st.find(id) != st.end());
auto it = st.erase(st.find(id));
int t = it == st.begin() ? 0 : a[*prev(it)].l;
int q = it == st.end() ? n + 1 : *it;
setValue(a[id].l, -1, 1, 1, m);
int y = seg2::binary(id, n, t, 1, 1, n);
while (y < q) {
enable(y);
seg2::disable(y);
t = a[y].l;
y = seg2::binary(id, n, t, 1, 1, n);
}
}
int binary(int L, int R, int v, int p, int l, int r) {
if (L <= l && r <= R) {
if (maxr[p] <= v) return m + 1;
if (l == r) return l;
}
int mid = (l + r) >> 1;
pushdown(p);
int ret = L <= mid ? binary(L, R, v, p << 1, l, mid) : m + 1;
if (ret <= m) return ret;
return mid < R ? binary(L, R, v, p << 1 | 1, mid + 1, r) : m + 1;
}
void plant(int pos) {
debug("plant(pos = %d)\n", pos);
// forall range, l <= pos < r
int len = hua[pos] - hua[pos - 1]; // hua[], 0-indexed
fen.add(pos, len);
int res = binary(1, pos, pos, 1, 1, m);
if (res <= pos) modify(res, pos, len, 1, 1, m);
}
int qrymax() { return wh[ans[1].second]; }
};
int main() {
#ifndef LOCAL
#ifndef NF
freopen("ds.in", "r", stdin);
freopen("ds.out", "w", stdout);
#endif
cin.tie(nullptr)->sync_with_stdio(false);
#endif
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i].l >> a[i].r, a[i].id = i, hua << a[i].l << a[i].r;
m = (int)hua.build();
for (int i = 1; i <= n; i++) a[i].l = (int)hua(a[i].l) + 1;
for (int i = 1; i <= n; i++) a[i].r = (int)hua(a[i].r) + 1;
auto key = [](auto&& self) { return make_tuple(self.r, -self.l, self.id); };
sort(a + 1, a + n + 1, [&](auto&& lhs, auto&& rhs) { return key(lhs) < key(rhs); }); // std::forward /lh
for (int i = 1; i <= n; i++) wh[a[i].id] = i;
for (int i = 1; i <= m; i++) nxt[i] = i;
seg1::build(1, 1, m);
seg2::build(1, 1, n);
for (int i = 1; i <= n; i++) {
if (st.empty() || a[*st.rbegin()].l < a[i].l) seg1::enable(i);
else seg2::enable(i);
}
for (int t = 1; t <= n; t++) {
int pos = seg1::qrymax();
cout << a[pos].id << " \n"[t == n];
int now = findnxt(a[pos].l);
while (now < a[pos].r) {
seg1::plant(now);
nxt[now] = now + 1;
now = findnxt(now);
}
seg1::disable(pos);
#ifdef LOCAL
for (int x : st) debug("%d ", a[x].id);
debug("\n");
for (int x : st) debug("[%d, %d] ", a[x].l, a[x].r);
debug("\n");
#endif
}
return 0;
}
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/18450510/solution-SS241006D