【大联盟】20230706 Interesting DS Problem(interesting) QOJ2559 【Endless Road】

发布时间 2023-07-22 17:32:21作者: zhaohaikun

题目描述

here

题解

首先,我们对所有区间离散化,删除一个区间时,我们暴力删除内部还存在的子区间。

如果没有区间包含是好做的,因为我们删除一个子区间时,将区间按照左端点排序,可发现包含这个子区间的区间是连续的一个区间。

现在考虑有区间包含怎么做。我们考虑维护出当前所有不包含别的区间的集合。因为若一个区间包含另一个区间,那么它一定在另一个区间之后删除,所以我们当前就不需要管它了。

我们找到当前要删除的区间后,我们就加入新的不包含别的区间的区间。有个暴力做法是主席树优化建图。不过还有别的做法,我们找到按照左端点排序的上一个区间 \([l_1,r_1]\) 和下一个区间 \([l_2,r_2]\),则我们每次找到剩下区间 \([l',r']\),满足 \(r'<r_2\),于是显然满足 \(l'<l_2\),并且是所有可行区间中 \(l'\) 最大的,若 \(l'>l_1\) 则结束。然后更新 \(l_2\leftarrow l',r_2\leftarrow r'\)

容易发现,这样可以找到所有新的合法区间。因为新的合法区间需要满足只包含 \([l,r]\),不包含别的区间,也就是不包含按左端点排序后与 \([l,r]\) 相邻的两个区间。

时间复杂度 \(O(n\log n)\)

代码

记录

#include <bits/stdc++.h>
#define ls num << 1
#define rs ls | 1
#define li ls, l, mid
#define ri rs, mid + 1, r
#define SZ(x) (int) x.size() - 1
#define all(x) x.begin(), x.end()
#define ms(x, y) memset(x, y, sizeof x)
#define F(i, x, y) for (int i = (x); i <= (y); i++)
#define DF(i, x, y) for (int i = (x); i >= (y); i--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
template <typename T> void chkmax(T& x, T y) { x = max(x, y); }
template <typename T> void chkmin(T& x, T y) { x = min(x, y); }
template <typename T> void read(T &x) {
	x = 0; int f = 1; char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
const int N = 5e5 + 10;
pair <int, int> a[N], b[N];
int id[N], seg1[N << 2], t[N], seg2[N << 2], ss[N << 2], tmp[N], tot, tag[N << 2], maxn[N << 2];
void add(int x, int y) {
	for (; x <= tot; x += x & -x) t[x] += y;
}
int query(int x) {
	int ans = 0;
	for (; x; x -= x & -x) ans += t[x];
	return ans;
}
void pushup1(int num) {
	if (seg1[ls] && (!seg1[rs] || a[seg1[ls]].second < a[seg1[rs]].second)) seg1[num] = seg1[ls];
	else seg1[num] = seg1[rs];
}
priority_queue <pair <int, int>, vector <pair <int, int>>, greater <pair <int, int>>> tt[N << 2];
void modify1(int num, int l, int r, int x) {
	if (l == r) {
		tt[num].emplace(a[x].second, x);
		seg1[num] = tt[num].top().second;
		return;
	} int mid = (l + r) >> 1;
	if (mid >= a[x].first) modify1(li, x);
	else modify1(ri, x);
	pushup1(num);
}
void mmodify1(int num, int l, int r, int x) {
	if (l == r) {
		tt[num].pop();
		seg1[num] = tt[num].size() ? tt[num].top().second : 0;
		return;
	} int mid = (l + r) >> 1;
	if (mid >= a[x].first) mmodify1(li, x);
	else mmodify1(ri, x);
	pushup1(num);
}
int query1(int num, int l, int r, int x, int y) {
	if (!seg1[num] || a[seg1[num]].second >= y) return -1;
	if (l == r) return seg1[num];
	int mid = (l + r) >> 1;
	if (mid + 1 < x) {
		int t = query1(ri, x, y);
		if (~t) return t;
	}
	return query1(li, x, y);
}
void down(int num, int x) {
	tag[num] += x;
	seg2[num] += x;
}
void pushdown(int num) {
	if (tag[num]) {
		down(ls, tag[num]), down(rs, tag[num]);
		tag[num] = 0;
	}
}
void pushup2(int num) {
	if ((seg2[ls] < seg2[rs]) || (seg2[ls] == seg2[rs] && id[ss[ls]] < id[ss[rs]])) {
		seg2[num] = seg2[ls];
		ss[num] = ss[ls];
	} else {
		seg2[num] = seg2[rs];
		ss[num] = ss[rs];
	}
	maxn[num] = max(maxn[ls], maxn[rs]);
}
void modify2(int num, int l, int r, int x, int y) {
	if (l == r) {
		seg2[num] = y;
		maxn[num] = a[x].second - 1;
		if (y == 1e9) ss[num] = 0;
		else ss[num] = x;
		return;
	}
	pushdown(num);
	int mid = (l + r) >> 1;
	if (mid >= a[x].first) modify2(li, x, y);
	else modify2(ri, x, y);
	pushup2(num);
}
void change(int num, int l, int r, int L, int R, int x) {
	if (L <= l && r <= R) return down(num, x);
	pushdown(num);
	int mid = (l + r) >> 1;
	if (mid >= L) change(li, L, R, x);
	if (mid < R) change(ri, L, R, x);
	pushup2(num);
}
int prv(int num, int l, int r, int x) {
	if (!ss[num]) return -1;
	if (l == r) return ss[num];
	int mid = (l + r) >> 1;
	if (mid + 1 < a[x].first) {
		int t = prv(ri, x);
		if (~t) return t;
	}
	return prv(li, x);
}
int nxt(int num, int l, int r, int x) {
	if (!ss[num]) return -1;
	if (l == r) return ss[num];
	int mid = (l + r) >> 1;
	if (mid > a[x].first) {
		int t = nxt(li, x);
		if (~t) return t;
	}
	return nxt(ri, x);
}
int query2(int num, int l, int r, int x) {
	if (l == r) return l;
	int mid = (l + r) >> 1;
	if (maxn[ls] >= x) return query2(li, x);
	return query2(ri, x);
}
bool vis[N];
void zhk() {
	tot = 0;
	int n; read(n);
	F(i, 1, n * 2) t[i] = 0, vis[i] = false;
	F(i, 1, n * 8) {
		seg2[i] = 1e9;
		seg1[i] = tag[i] = ss[i] = maxn[i] = 0;
		while (tt[i].size()) tt[i].pop();
	}
	F(i, 1, n) read(a[i].first), read(a[i].second), tmp[++tot] = a[i].first, tmp[++tot] = a[i].second, id[i] = i;
	sort(tmp + 1, tmp + tot + 1);
	tot = unique(tmp + 1, tmp + tot + 1) - tmp - 1;
	F(i, 1, n) a[i].first = lower_bound(tmp + 1, tmp + tot + 1, a[i].first) - tmp, a[i].second = lower_bound(tmp + 1, tmp + tot + 1, a[i].second) - tmp;
	sort(id + 1, id + n + 1, [&] (int x, int y) {
		if (a[x].first == a[y].first) return a[x].second > a[y].second;
		return a[x].first < a[y].first;
	});
	F(i, 1, n) b[i] = a[id[i]];
	swap(a, b);
	deque <int> q;
	set <int> s;
	F(i, 1, tot - 1) add(i, tmp[i + 1] - tmp[i]), s.insert(i);
	F(i, 1, n) {
		while (q.size() && a[q.back()].second >= a[i].second) q.pop_back();
		q.push_back(i);
	}
	ms(vis, false);
	for (int i: q) {
		vis[i] = true;
		modify2(1, 1, tot, i, tmp[a[i].second] - tmp[a[i].first]);
	}
	F(i, 1, n)
		if (!vis[i]) modify1(1, 1, tot, i);
	F(i, 1, n) {
		int t = ss[1];
		cout << id[t] << " ";
		modify2(1, 1, tot, t, 1e9);
		int p = a[t].first == 1 ? -1 : prv(1, 1, tot, t), q = a[t].first == tot ? -1 : nxt(1, 1, tot, t);
		while (true) {
			int t = query1(1, 1, tot, (~q) ? a[q].first : tot + 1, (~q) ? a[q].second : tot + 1);
			if (t == -1) break;
			if ((~p) && a[t].first <= a[p].first) break;
			mmodify1(1, 1, tot, t);
			modify2(1, 1, tot, t, query(a[t].second - 1) - query(a[t].first - 1));
			q = t;
		}
		while (true) {
			auto pos = s.lower_bound(a[t].first);
			if (pos == s.end() || *pos >= a[t].second) break;
			int x = *pos; s.erase(pos);
			add(x, tmp[x] - tmp[x + 1]);
			int pp = query2(1, 1, tot, x);
			change(1, 1, tot, pp, x, tmp[x] - tmp[x + 1]);
		}
	}
	cout << '\n';
}
signed main() {
	// freopen("interesting.in", "r", stdin);
	// freopen("interesting.out", "w", stdout);
	int T, sid; read(T);
	while (T--) zhk();
	return 0;
}