题解 gym102900J 【Octasection】
一个最 naive 的暴力是把 \(l_{1, i}, l_{2, i}, l_{3, i}\) 分别拿出来离散化后枚举判断,时间复杂度为 \(O(n^4)\)。
考虑减小枚举量:可以发现在枚举第一维后,对于一个还不合法的项 \(i\),若第二维 \(\not\in [l_{2, i}, r_{2, i}]\),第三维就必须选 \([l_{3, i}, r_{3, i}]\) 中的值。于是枚举第一维后扫描线即可。时间复杂度为 \(O(n^2 \log n)\)。
但这样还是太慢了,注意到项的不合法位置为前后缀各一处,考虑将问题转化为:
- 我们对第二维的每个位置维护另一维可以选的位置,这里我们用若干区间的交来描述。
- 第二维区间加入区间。
- 第二维区间删除区间。
- 询问是否存在一个第二维的位置,使得其区间交非空。
考虑线段树分治将第二种操作变为撤销第二维区间加入区间的操作。
首先考虑操作一、三。一个自然的想法是对第二维的每个位置维护 \([L_i, R_i]\) 表示区间交的左右端点,则操作一相当于区间对 \(L_i\) chkmax、对 \(R_i\) chkmin,操作三相当于询问 \(\displaystyle\max_i (R_i - L_i) \geq 0\) 是否成立。
注意到这里的操作区间一定是一个前缀或一个后缀,于是 \(L_i\) 单谷、\(R_i\) 单峰,我们每次操作的有效部分要么是全体、要么是前后缀,于是线段树上二分出修改区间,问题转化为区间赋值,这是容易维护的。
- 事实上我们实现时并不需要真的在线段树上二分:直接暴力递归,遇到 \(L_i\) 最小值 \(\geq k\)、\(R_i\) 最大值 \(\leq k\) 的情况就直接返回。
用栈维护所有有修改的线段树节点,撤销时弹栈即可。时间复杂度为 \(O(n \log^2 n)\)。
代码:
#include <iostream>
#include <algorithm>
#include <stack>
#include <vector>
#include <cstdio>
using namespace std;
typedef struct Rectangle_tag {
	int x1;
	int x2;
	int y1;
	int y2;
	Rectangle_tag(){}
	Rectangle_tag(int x1_, int x2_, int y1_, int y2_){
		x1 = x1_;
		x2 = x2_;
		y1 = y1_;
		y2 = y2_;
	}
} Rectangle;
namespace SolveY {
	typedef struct {
		int l;
		int r;
		int chkmaxl;
		int chkminr;
		int minl;
		int maxl;
		int minr;
		int maxr;
		pair<int, int> pr1;
		pair<int, int> pr2;
		pair<int, int> pr3;
	} SegmentTreeNode;
	typedef struct StackNode_tag {
		int tm;
		int pos;
		SegmentTreeNode info;
		StackNode_tag(int tm_, int pos_, SegmentTreeNode info_){
			tm = tm_;
			pos = pos_;
			info = info_;
		}
	} StackNode;
	int top = 0, tm;
	SegmentTreeNode tree[400007];
	stack<StackNode> s;
	inline void update(int x){
		int ls = x * 2, rs = x * 2 + 1;
		tree[x].minl = min(tree[ls].minl, tree[rs].minl);
		tree[x].maxl = max(tree[ls].maxl, tree[rs].maxl);
		tree[x].minr = min(tree[ls].minr, tree[rs].minr);
		tree[x].maxr = max(tree[ls].maxr, tree[rs].maxr);
		tree[x].pr1 = min(tree[ls].pr1, tree[rs].pr1);
		tree[x].pr2 = max(tree[ls].pr2, tree[rs].pr2);
		tree[x].pr3 = max(tree[ls].pr3, tree[rs].pr3);
	}
	void build(int x, int l, int r, int n){
		tree[x].l = l;
		tree[x].r = r;
		tree[x].chkmaxl = 0;
		tree[x].chkminr = 0x7fffffff;
		if (l == r){
			tree[x].minl = tree[x].maxl = 0;
			tree[x].minr = tree[x].maxr = n;
			tree[x].pr1 = make_pair(0, l);
			tree[x].pr2 = tree[x].pr3 = make_pair(n, l);
			return;
		}
		int mid = (l + r) >> 1;
		build(x * 2, l, mid, n);
		build(x * 2 + 1, mid + 1, r, n);
		update(x);
	}
	inline void push(int x){
		s.push(StackNode(tm, x, tree[x]));
	}
	inline bool check(int x){
		return tree[x].chkmaxl != 0 || tree[x].chkminr != 0x7fffffff;
	}
	inline void push_chkmaxl(int x, int k){
		tree[x].chkmaxl = tree[x].minl = tree[x].maxl = tree[x].pr1.first = k;
		tree[x].pr3 = make_pair(tree[x].pr2.first - k, tree[x].pr2.second);
	}
	inline void push_chkminr(int x, int k){
		tree[x].chkminr = tree[x].minr = tree[x].maxr = tree[x].pr2.first = k;
		tree[x].pr3 = make_pair(k - tree[x].pr1.first, tree[x].pr1.second);
	}
	inline void pushdown(int x){
		int ls = x * 2, rs = x * 2 + 1;
		if (tree[x].chkmaxl != 0){
			push_chkmaxl(ls, tree[x].chkmaxl);
			push_chkmaxl(rs, tree[x].chkmaxl);
			tree[x].chkmaxl = 0;
		}
		if (tree[x].chkminr != 0x7fffffff){
			push_chkminr(ls, tree[x].chkminr);
			push_chkminr(rs, tree[x].chkminr);
			tree[x].chkminr = 0x7fffffff;
		}
	}
	void chkmaxl(int x, int l, int r, int k){
		if (tree[x].minl >= k) return;
		push(x);
		if (l <= tree[x].l && tree[x].r <= r && tree[x].maxl < k){
			push_chkmaxl(x, k);
			return;
		}
		int mid = (tree[x].l + tree[x].r) >> 1;
		if (check(x)){
			push(x * 2);
			push(x * 2 + 1);
			pushdown(x);
		}
		if (l <= mid) chkmaxl(x * 2, l, r, k);
		if (r > mid) chkmaxl(x * 2 + 1, l, r, k);
		update(x);
	}
	void chkminr(int x, int l, int r, int k){
		if (tree[x].maxr <= k) return;
		push(x);
		if (l <= tree[x].l && tree[x].r <= r && tree[x].minr > k){
			push_chkminr(x, k);
			return;
		}
		int mid = (tree[x].l + tree[x].r) >> 1;
		if (check(x)){
			push(x * 2);
			push(x * 2 + 1);
			pushdown(x);
		}
		if (l <= mid) chkminr(x * 2, l, r, k);
		if (r > mid) chkminr(x * 2 + 1, l, r, k);
		update(x);
	}
	int getl(int x, int pos){
		if (tree[x].l == tree[x].r) return tree[x].minl;
		pushdown(x);
		if (pos <= ((tree[x].l + tree[x].r) >> 1)) return getl(x * 2, pos);
		return getl(x * 2 + 1, pos);
	}
	inline bool rollback(){
		if (s.empty()) return false;
		StackNode cur = s.top();
		if (cur.tm != tm) return false;
		s.pop();
		tree[cur.pos] = cur.info;
		return true;
	}
}
int lst1[100007], lst2[100007], lst3[100007];
namespace SolveX {
	typedef struct {
		int l;
		int r;
		vector<Rectangle> v;
	} Node;
	Node tree[400007];
	void build(int x, int l, int r){
		tree[x].l = l;
		tree[x].r = r;
		if (l == r) return;
		int mid = (l + r) >> 1;
		build(x * 2, l, mid);
		build(x * 2 + 1, mid + 1, r);
	}
	void insert(int x, int l, int r, Rectangle rec){
		if (l <= tree[x].l && tree[x].r <= r){
			tree[x].v.push_back(rec);
			return;
		}
		int mid = (tree[x].l + tree[x].r) >> 1;
		if (l <= mid) insert(x * 2, l, r, rec);
		if (r > mid) insert(x * 2 + 1, l, r, rec);
	}
	void dfs(int x, int n){
		SolveY::tm++;
		for (register Rectangle i : tree[x].v){
			if (i.x1 > 1){
				SolveY::chkmaxl(1, 1, i.x1 - 1, i.y1);
				SolveY::chkminr(1, 1, i.x1 - 1, i.y2);
			}
			if (i.x2 < n){
				SolveY::chkmaxl(1, i.x2 + 1, n, i.y1);
				SolveY::chkminr(1, i.x2 + 1, n, i.y2);
			}
		}
		if (tree[x].l == tree[x].r){
			if (SolveY::tree[1].pr3.first >= 0){
				cout << "YES" << endl;
				cout << lst1[tree[x].l] << " " << lst2[SolveY::tree[1].pr3.second] << " " << lst3[SolveY::getl(1, SolveY::tree[1].pr3.second)];
				exit(0);
			}
		} else {
			dfs(x * 2, n);
			dfs(x * 2 + 1, n);
		}
		while (SolveY::rollback()) ;
		SolveY::tm--;
	}
}
int l1[100007], r1[100007], l2[100007], r2[100007], l3[100007], r3[100007];
int main(){
	int n, cnt1 = 0, cnt2 = 0, cnt3 = 0;
	scanf("%d", &n);
	for (register int i = 1; i <= n; i++){
		scanf("%d %d %d %d %d %d", &l1[i], &r1[i], &l2[i], &r2[i], &l3[i], &r3[i]);
		lst1[++cnt1] = l1[i];
		lst2[++cnt2] = l2[i];
		lst3[++cnt3] = l3[i];
	}
	sort(lst1 + 1, lst1 + cnt1 + 1);
	cnt1 = unique(lst1 + 1, lst1 + cnt1 + 1) - lst1 - 1;
	sort(lst2 + 1, lst2 + cnt2 + 1);
	cnt2 = unique(lst2 + 1, lst2 + cnt2 + 1) - lst2 - 1;
	sort(lst3 + 1, lst3 + cnt3 + 1);
	cnt3 = unique(lst3 + 1, lst3 + cnt3 + 1) - lst3 - 1;
	SolveX::build(1, 1, cnt1);
	for (register int i = 1; i <= n; i++){
		Rectangle rect;
		l1[i] = lower_bound(lst1 + 1, lst1 + cnt1 + 1, l1[i]) - lst1;
		r1[i] = upper_bound(lst1 + 1, lst1 + cnt1 + 1, r1[i]) - lst1 - 1;
		l2[i] = lower_bound(lst2 + 1, lst2 + cnt2 + 1, l2[i]) - lst2;
		r2[i] = upper_bound(lst2 + 1, lst2 + cnt2 + 1, r2[i]) - lst2 - 1;
		l3[i] = lower_bound(lst3 + 1, lst3 + cnt3 + 1, l3[i]) - lst3;
		r3[i] = upper_bound(lst3 + 1, lst3 + cnt3 + 1, r3[i]) - lst3 - 1;
		rect = Rectangle(l2[i], r2[i], l3[i], r3[i]);
		if (l1[i] > 1) SolveX::insert(1, 1, l1[i] - 1, rect);
		if (r1[i] < cnt1) SolveX::insert(1, r1[i] + 1, cnt1, rect);
	}
	SolveY::build(1, 1, cnt2, cnt3);
	SolveX::dfs(1, cnt2);
	cout << "NO";
	return 0;
}
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号