首页 > 其他分享 >矩形有交问题—CDQ

矩形有交问题—CDQ

时间:2022-11-30 22:55:35浏览次数:62  
标签:le int mid mx tag CDQ 矩形 有交

矩阵覆盖问题-CDQ分治

[COCI2018-2019#2] Sunčanje

题目描述

Slavko 做了一个不寻常的梦。在一个晴朗的早上,\(N\) 个白色的矩形一个接着一个爬上了 Slavko 家的屋顶,并在屋顶上晒太阳。每个矩形在屋顶都选定了一个位置,使得它的边与屋顶的棱角平行。有些矩形可能会覆盖在其它矩形所在的位置上。每个矩形的长、宽分别为 \(A_i,B_i\),其与屋顶左方和下方的棱角的距离分别为 \(X_i,Y_i\)。

日落后,矩形们从屋顶上下来,并睡了一觉。次日,它们发现,有些矩形变成了黄色,而有些仍为白色。变为黄色的矩形都是完全暴露在阳光下的。

请判断每个矩形是否变为了黄色。

输入格式

第一行输入正整数 \(N\),表示矩形的个数。

接下来的 \(N\) 行,每行输入整数 \(X_i,Y_i,A_i,B_i\)。输入顺序与登上屋顶的顺序一致。

输出格式

输出 \(N\) 行。其中,若第 \(i\) 个矩形变为黄色,则在第 \(i\) 行输出 DA,否则在该行输出 NE

样例 #1

样例输入 #1

5
1 1 4 2
6 1 1 1
2 2 2 3
3 4 3 2
4 0 1 2

样例输出 #1

NE
DA
NE
DA
DA

样例 #2

样例输入 #2

3
3 3 1 1
2 2 3 3
1 1 5 5

样例输出 #2

NE
NE
DA

提示

样例 1 解释

矩形 \(1,3\) 没有完全暴露在阳光下,因而它们没有变为黄色:

数据规模与约定

对于 \(10\%\) 的数据,\(N \le 10^4\)。

对于 \(100\%\) 的数据,\(1 \le N \le 10^5\),\(0 \le X_i,Y_i \le 10^9\),\(1 \le A_i,B_i \le 10^9\)。

说明

本题分值按 COCI 原题设置,满分 \(130\)。

题目译自 COCI2018-2019 CONTEST #2 T5 Sunčanje

分析

我们记矩阵序列为 \(A\) ,其中 \(A[i]=(x_1,y_1,x_2,y_2)(x_1\le x_2,y1\le y_2)\) ,为了方便,我们将 \(A[i]\) 的 \(x_1\) 写作 \(A[i,x_1]\) ,其余类似

那么矩阵 \(i\) 被矩阵 \(j\) 覆盖需要满足以下条件

\[\left\{ \begin{aligned} i<j\\ \left\{ \begin{aligned} A[i,x_1]&\le A[j,x_2] \\ A[j,x_1]&\le A[i,x_2] \\ \end{aligned} \right.\\ \left\{ \begin{aligned} A[i,y_1]&\le A[j,y_2] \\ A[j,y_1]&\le A[i,y_2] \\ \end{aligned} \right. \end{aligned} \right. \]

(在这里有一个细节,就是有可能一个矩形的右边和一个矩形的左边在同一直线上(亦或者一个矩形的上边和一个矩形的下边在同一直线上),但此时没有交点却仍然会被累加进入答案,故为了解决这个问题,可以把右上角整体缩一格,也即右上角的横纵坐标全部-1(这就是部分同志最后几个点过不了的原因));

考虑如何求解
这个玩意类似于偏序问题,考虑使用 CDQ 分治

若按照时间轴分治,则设分治两区间为 \([l,mid],[mid+1,r]\)

此时 \([l,mid]\) 的时间都早于 \([mid+1,r]\)

此时我们需要考虑后半区间对前半区间的影响,先用常规双指针套路维护限制条件 \(A[j,x_1]\le A[i,x_2]\)

将区间 \([l,mid]\) 按照 \(x_2\) 递增排序,区间 \([mid+1,r]\) 按照 \(x_1\) 递增排序,设两个指针分别为 \(L,R\)

采用双指针扫描,则 \([mid+1,R]\) 的矩形都满足对于 \(L\) 来说 \(A[L,x_2]\ge A[k,x_1]\) ,考虑判定在 \([mid+1,R]\) 中有无矩形可以覆盖 \(L\)

按照 \(CDQ\) 分治的套路我们需要数据结构来维护剩余的几个条件

\[\left\{ \begin{aligned} A[i,x_1]&\le A[j,x_2] \\ A[i,y_1]&\le A[j,y_2] \\ A[j,y_1]&\le A[i,y_2] \\ \end{aligned} \right. \]

这里由于限制条件就是要求矩形横向有交点,竖向有交点,而对于竖向有交点,可以转化为线段有交问题,考虑使用维护线段的数据结构——线段树

那,我们对区间 \([A[i,y_1],A[i,y_2]]\) 进行修改,只需要我们能够判定在区间 \([A[L,y_1],A[L,y_2]]\) 中有无大于等于 \(A[L,x_1]\) 的元素,这启发我们的线段树维护区间最大值,假设我们将区间 \([l',r']\) 的最大值记为 \(g[l',r']\) ,记 \(f[i]\) 表示第\(i\)个矩形是否被覆盖

那么就有 \(f[A[L,id]]|=A[L,x_1]\le g[A[L,y_1],A[L,y_2]]\)

统计完了之后将线段树全部清空为-1即可

最后,我们再来梳理一遍这个过程

  1. 离散化坐标
  2. 在CDQ分治中
  3. 左半区间按照\(x_2\)排,右半区间按\(x_1\)排
  4. 双指针扫描,使得\(A[L,x_2]\ge A[R,x_1]\)
  5. 在扫描的过程中不断在线段树的区间\([A[R,y_1],A[R,y_2]]\)上更新区间最大值
  6. 对于\(L\)查询区间\([A[L,x_1,x_2]]\)是否存在大于\(A[L,x_1]\)的值,存在也就表示\(L\)被覆盖
  7. 清空线段树

时间复杂度是\(O(n\log^2n)\),线段树常数大得一批,怪不得时间要求4s

#include<iostream>
#include<cstdio>
#include<algorithm>
#define scanf scanf_s
using namespace std;
#define N 1000050
struct node {
	int id, x1, x2, y1, y2;
}a[N];//矩阵
int b[N], c[N], cnt;//离散化
int f[N], n, m;
struct seg_tree {
	int mx, tag, lazy, l, r;
}t[N << 2];//线段树
#define lc x<<1
#define rc x<<1|1
void build(int l, int r, int x) {
	t[x] = { 0,0,-1,l,r };
	if (l == r)return;
	int mid = l + r >> 1;
	build(l, mid, lc);
	build(mid + 1, r, rc);
}
inline void pushup(int x) {
	t[x].mx = max(t[lc].mx, t[rc].mx);
}
inline void pushdown(seg_tree& a, seg_tree& b, seg_tree& c) {
	if (a.lazy != -1) {
		b.tag = c.tag = 0;
		b.mx = c.mx = 0;
		b.lazy = c.lazy = 0;
		a.lazy = -1;
	}
	b.tag = max(b.tag, a.tag);
	c.tag = max(c.tag, a.tag);
	b.mx = max(b.mx, a.tag);
	c.mx = max(c.mx, a.tag);
	a.tag = 0;
	return;
}
inline void pushdown(int x) {
	pushdown(t[x], t[lc], t[rc]);
}
void update(int x, int l, int r, int k) {
	if (l <= t[x].l && t[x].r <= r) {
		t[x].mx = max(t[x].mx, k);
		t[x].tag = max(t[x].tag, k);
		return;
	}
	pushdown(x);
	int mid = t[x].l + t[x].r >> 1;
	if (l <= mid)update(lc, l, r, k);
	if (mid < r)update(rc, l, r, k);
	pushup(x);
}
int find(int x, int l, int r) {
	if (l <= t[x].l && t[x].r <= r) {
		//		printf("%d %d %d %d %d\n", t[x].lazy, t[x].tag, t[x].l, t[x].r, t[x].mx);
		return t[x].mx;
	}
	int ans = -1, mid = t[x].l + t[x].r >> 1;
	pushdown(x);
	if (l <= mid)ans = max(ans, find(lc, l, r));
	if (mid < r)ans = max(ans, find(rc, l, r));
	pushup(x);
	return ans;
}
#undef lc
#undef rc
void init() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		int A, B, c, d;
		scanf("%d%d%d%d", &A, &B, &c, &d);
		c += A - 1, d += B - 1;
		a[i] = { i,A,c,B,d };
		b[++cnt] = A, b[++cnt] = B, b[++cnt] = c, b[++cnt] = d;
	}
	sort(b + 1, b + cnt + 1);
	cnt = unique(b + 1, b + cnt + 1) - b - 1;
	//	printf("%d\n", cnt);
	for (int i = 1; i <= n; i++) {
		a[i].x1 = lower_bound(b + 1, b + cnt + 1, a[i].x1) - b;
		a[i].y1 = lower_bound(b + 1, b + cnt + 1, a[i].y1) - b;
		a[i].x2 = lower_bound(b + 1, b + cnt + 1, a[i].x2) - b;
		a[i].y2 = lower_bound(b + 1, b + cnt + 1, a[i].y2) - b;
		//		printf("%d %d %d %d\n", a[i].x1, a[i].y1, a[i].x2, a[i].y2);
	}
}
bool cmp1(node a, node b) {
	return a.x1 < b.x1;
}
bool cmp2(node a, node b) {
	return a.x2 < b.x2;
}
void cdq(int l, int r) {
	if (l == r)return;
	int mid = l + r >> 1;
	cdq(l, mid);
	cdq(mid + 1, r);
	int L = l, R = mid + 1;
	sort(a + l, a + mid + 1, cmp2);
	sort(a + R, a + r + 1, cmp1);
	//	for (int i = l; i <= r; i++)printf("%d ", a[i].id);
	//	puts("");
	for (; L <= mid; L++) {
		while (a[R].x1 <= a[L].x2 && R <= r) {
			update(1, a[R].y1, a[R].y2, a[R].x2);
			R++;
		}
		f[a[L].id] |= find(1, a[L].y1, a[L].y2) >= a[L].x1;
		//	if (find(1, a[L].y1, a[L].y2) >= a[L].x1) {
		//		printf("%d %d %d\n", a[L].id, find(1, a[L].y1, a[L].y2), L-l);
		//	}
	}
	t[1].tag = t[1].mx = t[1].lazy = 0;
	pushdown(1);
	//	puts("Cleaded");
}
int main() {
	init();
	build(1, cnt << 1, 1);
	cdq(1, n);
	for (int i = 1; i <= n; i++) {
		if (f[i])puts("NE");
		else puts("DA");
	}
	return 0;
}

标签:le,int,mid,mx,tag,CDQ,矩形,有交
From: https://www.cnblogs.com/oierpyt/p/16940086.html

相关文章

  • 四根长度为3、两根长度为4、四根长度为7的木棍能围成多少种不同的矩形
    四根长度为3、两根长度为4、四根长度为7的木棍能围成多少种不同的矩形问题四根长度为3、两根长度为4、四根长度为7的木棍能围成多少种不同的矩形。无需每次用完所有木棍......
  • opencv 矩形标记
     importcv2fromPILimportImageimportpytesseractimportpyautoguiimportnumpyasnpimporttime#图片路径img=cv2.imread('Images/CAD2.png')xstart,......
  • 2142. 最小矩形覆盖
    题目链接2142.最小矩形覆盖已知平面上不共线的一组点的坐标,求覆盖这组点的面积最小的矩形。输出矩形的面积和四个顶点的坐标。输入格式第一行包含一个整数\(n\),表示......
  • canvas绘制圆角矩形
     canvas绘制圆角矩形Canvas并没有提供绘制圆角矩形的方法,但是通过观察,我们可以发现,其实我们可以将圆角矩形分为四段,可以通过使用arcTo来实现我们假设起点为x,y.绘......
  • 84.柱状图中最大的矩形 largest-rectangle-in-histogram
    问题描述84.柱状图中最大的矩形解题思路首先,要找最大矩形,即要找每个heights[i]所能构成的矩形面积的最大值:heights[i]所能构成的最大矩形,左侧,右侧必定都是连续的大于......
  • CDQ
    额。。。忘得差不多了1.陌上花开:如何去重:我们直接去重,然后对于每一类数,贡献再加上tot-1,我们直接对个数开桶即可。2.动态逆序对:下午一开就嘎嘎打,然后疯狂调,发现:我只考......
  • linux 中判断一组数据是否有交叉
     001、shell实现[root@pc1test2]#lsa.txt[root@pc1test2]#cata.txt##测试数据146108161720[root@pc1test2]#cata.txt|tr"""\n"|sed-e......
  • CDQ分治
    CDQ分治常用于解决多维偏序关系问题,以三维为例,第一维可以排序解决,第二维进行分治,第三位常用数据结构(树状数组)维护,于是也可以将动态带修改问题,离线处理,常默认时间为第一维。......
  • 【热力】基于matlab模拟矩形板上二维温度分布
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • CDQ分治
    0x00简介--是的,\(CDQ\)分治是一款由女oier\(CDQ\)引入的分治算法,可以利用分治让我们离线地解决一些在线数点问题--你说的对,但是面对强制在线的题目,\(C......