题解:QOJ10042 Scheduling
给定值域在 \(1e6\) 之内的 \(n\) 条线段,选出 \(n\) 个点 \(p_1, p_2, \dots, p_n\),满足 \(p_i \in [l_i, r_i)\) 且对于 \(i \neq j\) 有 \(|p_i - p_j| > 1\)。
对值域进行离散化,具体可以参考代码。
必然存在某些区间 \([L_i, R_i]\) 使得这些区间内必须按照 \(L_i, L_i + 2, L_i + 4, \dots, R_i\) 的方式选点。这些区间可以用一次扫描线求出来,并起来得到极大区间。全部填充好之后,考虑剩下的区间怎么填。对于一个区间 \([L, R]\),如果长度为奇数,那么放满必然是最优的;不然的话会存在两个相邻的 0,剩下的位置是放满的。假设两个相邻的 0 位于下标 \(p - 1, p\),我们尝试找到最小的 \(p\) 使得对于所有 \(r \leq R\),\([l, r]\) 满足 Hall 定理。找 \(p\) 的过程也是一个扫描线,具体可以参考代码实现。
/* Good Game, Well Play. */
#include <bits/stdc++.h>
#define lowbit(x) ((x) & (-(x)))
using namespace std;
const int N = 600010;
typedef pair < int, int > PII;
int Type, T, n, m, res[N]; bitset < N > f, tag;
priority_queue < PII, vector < PII >, greater < PII > > pq;
struct Range
{
int l, r, id;
bool operator < (const Range &w) const {return r < w.r;}
bool operator > (const Range &w) const {return r > w.r;}
} rng[N]; vector < int > l_p[N];
inline bool cmp_range_l(Range u, Range v) {return u.l < v.l;}
struct Disc
{
int num[N], k;
inline void clear() {k = 0;}
inline void insert(int x) {num[++k] = x;}
inline int id_to_val(int x) {return num[x];}
inline int val_to_id(int x)
{
int l = 1, r = k, ps = 0;
while(l <= r)
{
int mid = (l + r) >> 1;
if(num[mid] <= x) ps = mid, l = mid + 1;
else r = mid - 1;
}
return ps;
}
}; Disc disc;
struct SegTree
{
int rt, idx;
struct SGT
{
int ls, rs, minn, tag, clr;
#define ls(x) tree[x].ls
#define rs(x) tree[x].rs
#define minn(x) tree[x].minn
#define tag(x) tree[x].tag
#define clr(x) tree[x].clr
} tree[N * 2];
inline void pushup(int now)
{minn(now) = min(minn(ls(now)), minn(rs(now)));}
inline void push_tag(int now, int cl, int tg)
{
if(cl) minn(now) = 0, tag(now) = 0, clr(now) = 1;
minn(now) += tg, tag(now) += tg;
}
inline void pushdown(int now)
{
push_tag(ls(now), clr(now), tag(now));
push_tag(rs(now), clr(now), tag(now));
clr(now) = tag(now) = 0;
}
inline void build(int &now, int l, int r)
{
now = ++idx; ls(now) = rs(now) = minn(now) = tag(now) = clr(now) = 0;
if(l == r) return ;
int mid = (l + r) >> 1;
build(ls(now), l, mid), build(rs(now), mid + 1, r);
}
inline void range_add(int now, int l, int r, int L, int R, int num)
{
// if(l == 1 && r == m) cerr << "range_add " << L << " " << R << " " << num << '\n';
if(L <= l && r <= R) {push_tag(now, 0, num); return ;}
pushdown(now); int mid = (l + r) >> 1;
if(L <= mid) range_add(ls(now), l, mid, L, R, num);
if(mid < R) range_add(rs(now), mid + 1, r, L, R, num);
pushup(now);
}
inline int find_pos(int now, int l, int r, int num)
{
if(minn(now) > num) return -1;
if(l == r) return l;
pushdown(now); int mid = (l + r) >> 1;
if(minn(ls(now)) <= num) return find_pos(ls(now), l, mid, num);
else return find_pos(rs(now), mid + 1, r, num);
}
inline void debug(int now, int l, int r)
{
if(l == r) {cerr << minn(now) << " "; return ;}
pushdown(now); int mid = (l + r) >> 1;
debug(ls(now), l, mid); debug(rs(now), mid + 1, r);
}
inline void _build(int m) {rt = idx = 0; build(rt, 1, m);}
inline void _clear() {push_tag(rt, 1, 0);}
inline void _range_add(int l, int r, int num) {range_add(rt, 1, m, l, r, num);}
inline int _find_pos(int num) {return find_pos(rt, 1, m, num);}
inline int _global_minn() {return minn(rt);}
inline void _debug() {cerr << "debug : "; debug(rt, 1, m); cerr << '\n';}
}; SegTree sgt;
struct Rngs
{
set < Range > con;
inline void clear() {con.clear();}
inline bool insert(Range cur)
{
// cerr << "Insert " << cur.l << " " << cur.r << '\n';
while(!con.empty() && con.rbegin() -> r >= cur.l - 1)
{
Range lst = *con.rbegin(); con.erase(prev(con.end()));
if(lst.r % 2 != cur.l % 2) return false; cur.l = lst.l;
}
con.insert(cur); return true;
}
}; Rngs rngs;
bool Impossible = false;
inline void work(int l, int r)
{
// cerr << "work " << l << " " << r << '\n';
// for(int i = 1; i <= m; ++i) cerr << f[i] << " "; cerr << '\n';
// sgt._debug();
if(l == 1) --l; if(r == m) ++r;
Impossible = false;
if(l % 2 == r % 2) {for(int i = l + 1; i <= r; i += 2) f[i] = 1;}
else
{
if(l == 1) {for(int i = l; i <= r; i += 2) f[i] = 1;}
else if(r == m) {for(int i = r; i >= l; i -= 2) f[i] = 1;}
else
{
for(int i = l + 2; i <= r; i += 2) f[i] = 1;
vector < Range > opts; int lim = l - 1, dv = 0;
for(int i = l; i <= r; ++i)
{
if(f[i])
{
// cerr << "A : " << i << '\n';
sgt._range_add(1, i, 1);
opts.push_back({1, i, 1});
}
for(int j : l_p[i])
{
// cerr << "B : " << i << " " << j << '\n';
sgt._range_add(1, j, -1);
opts.push_back({1, j, -1});
}
// cerr << "! " << i << " " << sgt._global_minn() << '\n';
if(sgt._global_minn() < 0) lim = i;
}
dv = lim + 1; if(dv % 2 == l % 2) ++dv;
if(dv > r) Impossible = true;
for(Range rng : opts) sgt._range_add(rng.l, rng.r, -rng.id);
for(int i = l; i <= r; ++i) f[i] = 0;
for(int i = dv - 2; i >= l; i -= 2) f[i] = 1;
for(int i = dv + 1; i <= r; i += 2) f[i] = 1;
}
}
for(int i = l; i <= r; ++i)
{
if(f[i]) sgt._range_add(1, i, 1);
for(int j : l_p[i]) sgt._range_add(1, j, -1);
}
// sgt._debug();
}
inline void sol()
{
cin >> n;
for(int i = 1; i <= n; ++i) cin >> rng[i].l >> rng[i].r, rng[i].id = i, --rng[i].r;
sort(rng + 1, rng + n + 1, cmp_range_l);
// 离散化
int ps = 0; disc.clear();
for(int i = 1; i <= n; ++i)
{
ps = max(ps, rng[i].l);
for(int j = 1; j <= 3; ++j) disc.insert(ps++);
}
m = disc.k; for(int i = 0; i <= m + 1; ++i) f[i] = tag[i] = 0;
for(int i = 1; i <= n; ++i) rng[i].l = disc.val_to_id(rng[i].l), rng[i].r = disc.val_to_id(rng[i].r);
for(int i = 0; i <= m + 1; ++i) l_p[i].clear();
for(int i = 1; i <= n; ++i) l_p[rng[i].r].push_back(rng[i].l);
// cerr << "Disc : \n";
// for(int i = 1; i <= n; ++i) cerr << "-> " << rng[i].l << " " << rng[i].r << '\n';
// 找出已经确定的点
sgt._build(m); rngs.clear();
for(int r = 1; r <= m; ++r)
{
sgt._range_add(1, r, 1);
for(int l : l_p[r]) sgt._range_add(1, l, -2);
if(sgt._global_minn() < -1) {cout << -1 << '\n'; return ;}
else if(sgt._global_minn() == -1)
{
int p = sgt._find_pos(-1);
if(!rngs.insert({p, r})) {cout << -1 << '\n'; return ;}
}
}
for(Range rng : rngs.con)
for(int i = rng.l; i <= rng.r; ++i)
tag[i] = 1, f[i] = (i % 2 == rng.l % 2);
// 对于没有确定的区间,一一确定策略
sgt._clear();
for(int l = 1; l <= m; ++l)
{
if(tag[l])
{
if(f[l]) sgt._range_add(1, l, 1);
for(int i : l_p[l]) sgt._range_add(1, i, -1);
continue;
}
int r = l; while(r + 1 <= m && !tag[r + 1]) ++r;
work(l, r); l = r;
if(Impossible) {cout << -1 << '\n'; return ;}
}
// cerr << "f : "; for(int i = 1; i <= m; ++i) cerr << f[i] << " "; cerr << '\n';
// 贪心匹配
while(!pq.empty()) pq.pop();
for(int i = 1, j = 1; i <= m; ++i)
{
while(j <= n && rng[j].l <= i)
pq.push({rng[j].r, rng[j].id}), ++j;
if(f[i] && pq.size())
{
if(pq.top().first < i) {cout << -1 << '\n'; return ;}
res[pq.top().second] = disc.id_to_val(i); pq.pop();
}
}
if(pq.size()) {cout << -1 << '\n'; return ;}
// 输出方案
for(int i = 1; i <= n; ++i) cout << res[i] << " "; cout << '\n';
}
int main()
{
// freopen("research.in", "r", stdin);
// freopen("research.out", "w", stdout);
// freopen("text.in", "r", stdin);
// freopen("prog.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> Type >> T;
while(T--) sol();
return 0;
}
/*
0 1
5
16 32
36 38
35 37
30 31
1 42
1 4
3
1 3
1 7
2 4
2
1 3
2 3
4
1 5
2 6
3 4
4 7
2
1 5
2 3
*/

浙公网安备 33010602011771号