题解: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
*/
posted @ 2025-02-14 17:35  隱貓柒  阅读(51)  评论(0)    收藏  举报