Gym 102028J scanning line / two-dimensional differential equation solution +

The meaning of problems: there is a two-dimensional plane, and n operations each will select a rectangle, so that part of the two-dimensional plane is covered. Now you can cancel the operation two of them, at least ask how many pieces place will be covered?

Ideas: Official concise solution to a problem, would not elaborate: https://codeforces.com/blog/entry/63729 .

Here the focus record what trick of two approaches.

1: Two-dimensional solutions of differential equations +

Dimensional difference: Suppose a number of rectangular add [(x1, y1), (x2, y2)], then the (x1, y1), (x2 + 1, y2 + 1) plus 1, (x1, y2 + 1), (x2 +1, y1) minus 1. Scanning time, cnt [i] [j] + = cnt [i - 1] [j], cnt [i] [j] + = cnt [i] [j - 1], cnt [i] [j] - = cnt [i - 1] [j - 1], so a linear scan over each point can know how many times is covered.

Solving equations: one point covered only know how many times is of no use, we need to know the specific plan coverage. For only covered once it is easy to know. But for the two covering it? We use and record and squares of the way, so that by solving the equation to know the number of the positions which the two numbers.

Code:

#include <bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
#define db double
#define pii pair<int, int>
using namespace std;
const int maxn = 1510;
LL sqr[maxn][maxn], sum[maxn][maxn], cnt[maxn][maxn];
LL cnt0, num[300010];
void add(int x, int y, LL val, LL flag) {
	cnt[x][y] += flag;
	sum[x][y] += val * flag;
	sqr[x][y] += val * val * flag; 
}
void update(int x1, int y1, int x2, int y2, LL flag) {
	cnt[x1][y1] += flag * cnt[x2][y2];
	sum[x1][y1] += flag * sum[x2][y2];
	sqr[x1][y1] += flag * sqr[x2][y2];
}
vector<pii> a;
int main () {
	int T, n, m, x1, y1, x2, y2;
	LL ans;
	scanf("%d", &T);
	while(T--) {
		scanf("%d%d", &n, &m);
		a.clear(), ans = 0, cnt0 = 0;
		for (int i = 1; i <= n; i++)
			whether [i] = 0;
		for (int i = 1; i <= m; i++) {
			for (int j = 1; j <= m; j++)
				sqr[i][j] = sum[i][j] = cnt[i][j] = 0;
		}
		for (int i = 1; i <= n; i++) {
			scanf("%d%d%d%d", &x1, &x2, &y1, &y2);
		 	add(x1, y1, i, 1), add(x2 + 1, y2 + 1, i, 1);
		 	add(x1, y2 + 1, i, -1), add(x2 + 1, y1, i, -1);
		}
		for (int i = 1; i <= m; i++)
			for (int j = 1; j <= m; j++) {
				update(i, j, i - 1, j, 1);
				update(i, j, i, j - 1, 1);
				update(i, j, i - 1, j - 1, -1);
				if(cnt[i][j] == 0) cnt0++;
				else if(cnt[i][j] == 1) {
					Surely [I [i] [j]] ++;
				} else if(cnt[i][j] == 2){
					LL tmp = sum[i][j] * sum[i][j] - sqr[i][j];
					LL x = (sum[i][j] + sqrt(sqr[i][j] - tmp)) / 2;
					LL y = sum[i][j] - x;
					if(x > y) swap(x, y);
					a.push_back(make_pair(x, y));
				}
			}
		LL res[3];
		nothing [0] = nothing [1] = nothing [2] = 0;
		for (int i = 1; i <= n; i++) {
			a [0] = num [i];
			sort (nothing, nothing + 3);
		}
		years = max (years res [1] + res [2]);
		sort(a.begin(), a.end());
		for (int i = 0, j = 0; i < a.size(); i = j) {
			while(j < a.size() && a[i] == a[j])j++;
			ans = max(ans, num[a[i].first] + num[a[i].second] + (j - i));
		}
		printf("%lld\n", m * m - cnt0 - ans);
	}
}

2: the scanning lines, the scanning lines we performed by covering a segment tree to know the number and specific programs and achieve coverage twice the scanning line is relatively subtle, and the kind of decentralized lazy numerals taste permanent marker bound. In particular such that for each rectangle [(x1, y1), (x2, y2)], we add a record number at the y1 position (x1, x2), delete the record number at the position y2 + 1. Each scan to a new location, we put in this position of the recording mark marked, as well as on the record you want to delete. After that, we traverse the tree line, we record the number 3, which is the number of 3 marker can devolve from the upper layer, so that when the bottom, if less than three decentralized marker, may be recorded at the corresponding position. If the current can be delegated from the upper mark has reached three, the direct return on the line.

Code:

#include <bits/stdc++.h>
#define ls (o << 1)
#define rs (o << 1 | 1)
#define ed tr[o].size() - 1
#define pii pair<int, int>
using namespace std;
const int maxn = 300010;
const int maxm = 1510;
vector<int> tr[maxm << 2], re_num[maxm], del_re[maxm];
vector<pii> a, re[maxm]; 
int the [maxn] num [maxn] cnt0;
void build(int o, int l, int r) {
	tr[o].clear();
	if(l == r) {
		return;
	}
	int mid = (l + r) >> 1;
	build(ls, l, mid);
	build(rs, mid + 1, r);
}
void add (int o, you're, you're down, you QL, you qr, you val) {
	if(l >= ql && r <= qr) {
		tr[o].push_back(val);
		return;
	}
	int mid = (l + r) >> 1;
	if(ql <= mid) add(ls, l, mid, ql, qr, val);
	if(qr > mid) add(rs, mid + 1, r, ql, qr, val);
}
void pushdown(int o, int& a1, int& a2, int& a3) {
	Q int [4];
	memset(q, 0, sizeof(q));
	while(tr[o].size() && q[0] < 3) {
		if(del[tr[o][ed]] == 1) tr[o].pop_back();
		else {
			q[++q[0]] = tr[o][ed];
			tr[o].pop_back();
		}
	}
	for (int i = 1; i <= q[0]; i++) {
		if(a1 == 0) a1 = q[i];
		else if(a2 == 0) a2 = q[i];
		else if(a3 == 0) a3 = q[i];
		tr[o].push_back(q[i]);
	}
}
DFS void (int o, you're, you're down, you're a1, a2 you, you a3) {
	if(a3 != 0) return;
	pushdown(o, a1, a2, a3);
	if(l == r) {
		if(a1 == 0) cnt0++;
		else if(a3 == 0) {
			if(a2 == 0) num[a1]++;
			else a.push_back(make_pair(min(a1, a2), max(a1, a2)));
		}
		return;
	}
	int mid = (l + r) >> 1;
	dfs(ls, l, mid, a1, a2, a3);
	dfs(rs, mid + 1, r, a1, a2, a3); 
}
int main () {
	int T, n, m, x1, x2, y1, y2;
	scanf("%d", &T);
	while(T--) {
		scanf("%d%d", &n, &m);
		build(1, 1, m);
		cnt0 = 0;
		a.clear();
		for (int i = 1; i <= m + 1; i++) {
			re_num[i].clear();
			del_re[i].clear();
			re[i].clear();
		}
		for (int i = 1; i <= n; i++) {
			scanf("%d%d%d%d", &x1, &x2, &y1, &y2);
			re[y1].push_back(make_pair(x1, x2));
			re_num[y1].push_back(i);
			del_re[y2 + 1].push_back(i);
			the [i] = 0;
			whether [i] = 0;
		}
		for (int i = 1; i <= m; i++) {
			for (int j = 0; j < re[i].size(); j++) {
				up x = re [i] [j];
				add(1, 1, m, x.first, x.second, re_num[i][j]);
			}
			for (int j = 0; j < del_re[i].size(); j++) {
				of [del_re [i] [j]] = 1;
			}
			dfs(1, 1, m, 0, 0, 0);
		}
		int tmp[3];
		memset(tmp, 0, sizeof(a));
		for (int i = 1; i <= n; i++) {
			tmp[0] = num[i];
			sort(tmp, tmp + 3);
		}
		int ans = tmp[1] + tmp[2];
		sort(a.begin(), a.end());
		for (int i = 0, j = 0; i < a.size(); i = j) {
			while(j < a.size() && a[i] == a[j]) j++;
			ans = max(ans, num[a[i].first] + num[a[i].second] + j - i);
		}
		printf("%d\n", m * m - cnt0 - ans);
	}
}

Complexity theory first slightly better than the second, but the reality is second faster than the first 400ms, probably because it pruned tree line.

Guess you like

Origin www.cnblogs.com/pkgunboat/p/11025745.html