luogu4125[WC2012]記憶中的水杉樹 線段樹 拓撲排序 掃描線 set

luogu4125[WC2012]記憶中的水杉樹 線段樹 拓撲排序 掃描線 set

題目傳送門

分析

題目大意:給定平面上若干條互不相交的線段。現在要把這些線段沿着上下左右四個方向移出這個平面。給定一種移動的方案,求這個方案最早在第幾步會導致線段相碰,並給出一種合法的方案使得移動過程中不存在任意兩條線段相碰。

做法:
先做第二問。不難發現存在一種只往一個方向移動方案。一種暴力的思路是O(n2)O(n^2)判斷兩條線段在某個方向上誰先移動誰後移動,建圖跑拓撲。

考慮用掃描線+set優化這個建圖的過程。考慮往上移動,當前掃描線爲x=x0x=x_0。我們可以將與x=x0x=x_0相交的線段按交點從下到上排序。然後順次連成一條鏈。

由於線段不相交,所以線段之間的相對順序不會隨着掃描線的移動而改變。所以只需要用setset維護當前線段的插入,刪除和相對順序即可。

對於第一問,考慮一條線段ll的不合法的情況。

我們沿着xx軸,yy軸分別做一遍掃描線,求出拓撲序。

假設它在其移動的方向上的左右邊界分別爲st,edst,ed,僅僅考慮後面的線段對前面的線段的影響,那麼實際上會衝突就意味着存在某個在其後面的線段,在其移動的方向上的拓撲序小於或者大於ll。大於小於要根據移動的方向來定。

倒着做,離散化之後用線段樹維護某個區間的拓撲序最值即可。

複雜度O(nlog)O(nlog)

代碼

#include<bits/stdc++.h>
const int N = 2e5 + 10, M = N << 2;
int ri() {
	char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int pr[N], d[N], q[N], nx[M], to[M], Mn, Mx, tot, tp, n;
int p[N], op[N], lx[N], rx[N], ox[N], ly[N], ry[N], oy[N], x_n, y_n;
void add(int u, int v) {to[++tp] = v; nx[tp] = pr[u]; pr[u] = tp; ++d[v];}
struct Segment_Tree {
	#define ls p << 1
	#define rs p << 1 | 1
	int tmn[M], tmx[M], mn[M], mx[M];
	void cmin(int &a, int b) {
		if(b && (!a || a > b))
			a = b;
	}
	void cmax(int &a, int b) {a = std::max(a, b);}
	void Tag(int p, int v) {cmin(tmn[p], v); cmax(tmx[p], v);}
	void Add(int a, int b) {cmin(Mn, a); cmax(Mx, b);}
	void Work(int p, int L, int R, int st, int ed, int v) {
		Add(tmn[p], tmx[p]);
		if(L == st && ed == R)
			return Add(mn[p], mx[p]), Tag(p, v);
		int m = L + R >> 1; cmin(mn[p], v); cmax(mx[p], v);
		if(st <= m)
			Work(ls, L, m, st, std::min(ed, m), v);
		if(ed > m)
			Work(rs, m + 1, R, std::max(st, m + 1), ed, v);
	}
}T1, T2;
int nw;
struct Point {int x, y;}a[N], b[N];
struct Line {
	int i; double k, b;
	bool operator < (const Line &a) const {return k * nw + b < a.k * nw + a.b;}
	bool operator == (const Line &b) {return i == b.i;}
};
std::vector<Line>in[N], out[N];
void Work(int *l, int *r, int *o, int &tot) {
	#define F(x) std::lower_bound(c + 1, c + tot + 1, x) - c;
	#define pb push_back
	static int c[M]; 
	std::set<Line>s;
	std::set<Line>::iterator it;
	tot = tp = 0;
	for(int i = 1;i <= n; ++i)
		c[++tot] = a[i].x + 1, c[++tot] = b[i].x;
	std::sort(c + 1, c + tot + 1);
	tot = std::unique(c + 1, c + tot + 1) - c - 1;
	for(int i = 1;i <= n; ++i) {
		l[i] = F(a[i].x + 1); r[i] = F(b[i].x);
		Line u; u.i = i; pr[i] = d[i] = 0;
		u.k = (a[i].y - b[i].y) / (double) (a[i].x - b[i].x);
		u.b = a[i].y - a[i].x * u.k;
		in[l[i]].pb(u); out[r[i]].pb(u);
	}
	for(int i = 1;i <= tot; ++i) {
		nw = c[i];
		for(Line u : in[i]) {
			it = s.insert(u).first;
			if(next(it) != s.end())
				add(u.i, next(it)->i);
			if(it != s.begin())
				add(prev(it)->i, u.i);
		}
		for(Line u : out[i]) 
			s.erase(u);
		in[i].clear(); out[i].clear();
	}
	int L = 1, R = 0;
	for(int i = 1;i <= n; ++i)
		if(!d[i])
			q[++R] = i, o[i] = R;
	for(int u = q[L]; L <= R; u = q[++L])
		for(int i = pr[u]; i; i = nx[i])
			if(!--d[to[i]])
				q[++R] = to[i], o[to[i]] = R;
}
int main() {
	n = ri();
	for(int i = 1;i <= n; ++i) {
		a[i].x = ri(); a[i].y = ri();
		b[i].x = ri(); b[i].y = ri();
		if(a[i].x > b[i].x)
			std::swap(a[i], b[i]);
	}
	Work(lx, rx, ox, x_n);
	for(int i = 1;i <= n; ++i) {
		std::swap(a[i].x, a[i].y);
		std::swap(b[i].x, b[i].y);
		if(a[i].x > b[i].x)
			std::swap(a[i], b[i]);
	}
	Work(ly, ry, oy, y_n);
	for(int i = 1;i <= n; ++i)
		p[i] = ri(), op[i] = ri();
	int ans = 0;
	for(int i = n;i; --i) {
		int u = p[i];
		if(op[i] & 1) {
			Mx = 0; Mn = n; T1.Work(1, 1, x_n, lx[u], rx[u], ox[u]);
			if(op[i] == 1 && Mx > ox[u] || op[i] == 3 && Mn < ox[u])
				ans = i;
			T2.Work(1, 1, y_n, ly[u], ry[u], oy[u]);
		}
		else {
			Mx = 0; Mn = n; T2.Work(1, 1, y_n, ly[u], ry[u], oy[u]);
			if(op[i] == 2 && Mx > oy[u] || op[i] == 0 && Mn < oy[u])
				ans = i;
			T1.Work(1, 1, x_n, lx[u], rx[u], ox[u]);
		}
	}
	printf("%d\n", ans);
	for(int i = 1;i <= n; ++i)
		printf("%d 0\n", q[i]);
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章