[COCI2018-2019#2] Sunčanje

前言

好久没写得这么爽了~

题目

洛谷

LOJ

讲解

在我看来,这是一道码农题。

对于每个矩形,我们考虑计算出顺序在它之后(即可能将其覆盖)没有与它相交的矩形个数,我们将其取名为合法矩形,然后与顺序在它之后的矩形个数比较即可得出答案。

考虑容斥。

对于每个矩形,我们可以将其四条边无限延长,然后整个平面就被分为了 \(9\) 个格子。对于上下左右四个方向各三个格子统计出有多少个合法矩形,记录下来。

显然四个角的合法矩形被计算了两次,减掉即可。这就是个简单的偏序问题了,使用 \(\tt cdq\) 即可求解。

小优化:在 \(\tt cdq\) 过程中,显然可以使用归并排序优化时间,当然不优化也行,这道题时限很宽。

注意 \(\tt cdq\) 排序时的顺序,求解时的边界问题以及树状数组的清空(因为我都挂过qwq)。

\(\tt cdq\) 套树状数组,时间复杂度是 \(O(n\log^2n)\)

代码

我的代码实现过于冗长,主要是因为四个角打了四个 \(\tt cdq\)。 /jk

而且我为了方便,将整个数组翻转了,看代码时不要误解了。

//12252024832524
#include <cstdio>
#include <cstring>
#include <algorithm>
#define TT template<typename T>
using namespace std; 

typedef long long LL;
const int MAXN = 200005;
int n,lenx,leny;
int lshx[MAXN],lshy[MAXN];

LL Read()
{
	LL x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

int b[MAXN];
int lowbit(int x){return (x & -x);}
void Add(int x,int M,int val){for(int i = x;i <= M;i += lowbit(i)) b[i] += val;}
int Sum(int x){int ret = 0;for(int i = x;i >= 1;i -= lowbit(i)) ret += b[i]; return ret;}
void clr(int x){for(int i = 1;i <= x;++ i) b[i] = 0;}
int cnt[MAXN];
struct Rectangle 
{
	int x,y,x2,y2;//lower left,upper right,ID
}c[MAXN];
struct node
{
	int x,y,f,ID,ori;//f=1:calculate,f=0:update
	node(){}
	node(int x1,int y1,int f1,int ID1,int ori1){
		x = x1;
		y = y1;
		f = f1;
		ID = ID1;
		ori = ori1;
	}
}p[MAXN],q[MAXN];

void cdq1(int l,int r)//upper left
{
	if(l == r) return;
	int mid = (l+r) >> 1;
	cdq1(l,mid); cdq1(mid+1,r);
	int I = l,J = mid+1,K = l;
	while(I <= mid && J <= r)
		if(p[I].x < p[J].x || (p[I].x == p[J].x && p[I].ori < p[J].ori)) q[K++] = p[I++];//Pay attention to the order when x is equal to another. 
		else q[K++] = p[J++];
	while(I <= mid) q[K++] = p[I++];
	while(J <= r) q[K++] = p[J++];
	for(int i = l;i <= r;++ i) 
	{
		p[i] = q[i];
		if(!p[i].f && p[i].ori <= mid)
			Add(leny-p[i].y+1,leny,1);
		else if(p[i].f && p[i].ori > mid)
			cnt[p[i].ID] -= Sum(leny-p[i].y+1);
	}
	for(int i = l;i <= r;++ i) 
		if(!p[i].f && p[i].ori <= mid)
			Add(leny-p[i].y+1,leny,-1);
}
void cdq2(int l,int r)//lower left
{
	if(l == r) return;
	int mid = (l+r) >> 1;
	cdq2(l,mid); cdq2(mid+1,r);
	int I = l,J = mid+1,K = l;
	while(I <= mid && J <= r)
		if(p[I].x < p[J].x || (p[I].x == p[J].x && p[I].ori < p[J].ori)) q[K++] = p[I++];
		else q[K++] = p[J++];
	while(I <= mid) q[K++] = p[I++];
	while(J <= r) q[K++] = p[J++];
	for(int i = l;i <= r;++ i) 
	{
		p[i] = q[i];
		if(!p[i].f && p[i].ori <= mid)
			Add(p[i].y,leny,1);
		else if(p[i].f && p[i].ori > mid)
			cnt[p[i].ID] -= Sum(p[i].y);
	}
	for(int i = l;i <= r;++ i) 
		if(!p[i].f && p[i].ori <= mid)
			Add(p[i].y,leny,-1);
}
void cdq3(int l,int r)//upper right
{
	if(l == r) return;
	int mid = (l+r) >> 1;
	cdq3(l,mid); cdq3(mid+1,r);
	int I = l,J = mid+1,K = l;
	while(I <= mid && J <= r)
		if(p[I].x < p[J].x || (p[I].x == p[J].x && p[I].ori > p[J].ori)) q[K++] = p[I++];
		else q[K++] = p[J++];
	while(I <= mid) q[K++] = p[I++];
	while(J <= r) q[K++] = p[J++];
	for(int i = r;i >= l;-- i) 
	{
		p[i] = q[i];
		if(!p[i].f && p[i].ori <= mid)
			Add(leny-p[i].y+1,leny,1);
		else if(p[i].f && p[i].ori > mid)
			cnt[p[i].ID] -= Sum(leny-p[i].y+1);
	}
	for(int i = r;i >= l;-- i) 
		if(!p[i].f && p[i].ori <= mid)
			Add(leny-p[i].y+1,leny,-1);
}
void cdq4(int l,int r)//lower right
{
	if(l == r) return;
	int mid = (l+r) >> 1;
	cdq4(l,mid); cdq4(mid+1,r);
	int I = l,J = mid+1,K = l;
	while(I <= mid && J <= r)
		if(p[I].x < p[J].x || (p[I].x == p[J].x && p[I].ori > p[J].ori)) q[K++] = p[I++];
		else q[K++] = p[J++];
	while(I <= mid) q[K++] = p[I++];
	while(J <= r) q[K++] = p[J++];
	for(int i = r;i >= l;-- i) 
	{
		p[i] = q[i];
		if(!p[i].f && p[i].ori <= mid)
			Add(p[i].y,leny,1);
		else if(p[i].f && p[i].ori > mid)
			cnt[p[i].ID] -= Sum(p[i].y);
	}
	for(int i = r;i >= l;-- i) 
		if(!p[i].f && p[i].ori <= mid)
			Add(p[i].y,leny,-1);
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read();
	for(int i = n;i >= 1;-- i) 
	{
		c[i].x = Read(),c[i].y = Read(),c[i].x2 = Read(),c[i].y2 = Read();//reverse order
		c[i].x2 += c[i].x-1;
		c[i].y2 += c[i].y-1;
		lshx[i<<1] = c[i].x; lshx[(i<<1)-1] = c[i].x2;
		lshy[i<<1] = c[i].y; lshy[(i<<1)-1] = c[i].y2;
	}
	//Discretization 
	sort(lshx+1,lshx+(n<<1)+1); sort(lshy+1,lshy+(n<<1)+1);
	lenx = unique(lshx+1,lshx+(n<<1)+1) - lshx - 1; leny = unique(lshy+1,lshy+(n<<1)+1) - lshy - 1;
	for(int i = 1;i <= n;++ i) c[i].x = lower_bound(lshx+1,lshx+lenx+1,c[i].x) - lshx,c[i].x2 = lower_bound(lshx+1,lshx+lenx+1,c[i].x2) - lshx;
	for(int i = 1;i <= n;++ i) c[i].y = lower_bound(lshy+1,lshy+leny+1,c[i].y) - lshy,c[i].y2 = lower_bound(lshy+1,lshy+leny+1,c[i].y2) - lshy;
	//4 directions
	for(int i = 1;i <= n;++ i) cnt[i] += Sum(c[i].x-1),Add(c[i].x2,lenx,1); clr(lenx); //left
	for(int i = 1;i <= n;++ i) cnt[i] += Sum(lenx-c[i].x2),Add(lenx-c[i].x+1,lenx,1); clr(leny); //right
	for(int i = 1;i <= n;++ i) cnt[i] += Sum(c[i].y-1),Add(c[i].y2,leny,1); clr(leny); //down
	for(int i = 1;i <= n;++ i) cnt[i] += Sum(leny-c[i].y2),Add(leny-c[i].y+1,leny,1); clr(leny); //up
	//4 corners 
	for(int i = 1;i <= n;++ i) p[i<<1] = node(c[i].x-1,c[i].y2+1,1,i,i<<1),p[(i<<1)-1] = node(c[i].x2,c[i].y,0,i,(i<<1)-1); cdq1(1,n<<1);
	for(int i = 1;i <= n;++ i) p[i<<1] = node(c[i].x-1,c[i].y-1,1,i,i<<1),p[(i<<1)-1] = node(c[i].x2,c[i].y2,0,i,(i<<1)-1); cdq2(1,n<<1);
	for(int i = 1;i <= n;++ i) p[i<<1] = node(c[i].x2+1,c[i].y2+1,1,i,i<<1),p[(i<<1)-1] = node(c[i].x,c[i].y,0,i,(i<<1)-1); cdq3(1,n<<1);
	for(int i = 1;i <= n;++ i) p[i<<1] = node(c[i].x2+1,c[i].y-1,1,i,i<<1),p[(i<<1)-1] = node(c[i].x,c[i].y2,0,i,(i<<1)-1); cdq4(1,n<<1);
	//There are so many "+1" and "-1". Pay attention to the boundary.
	//print
	for(int i = n;i >= 1;-- i)
	{
		if(cnt[i] != i-1) printf("NE\n");
		else printf("DA\n");
	}
	return 0;
}
//sorry for my poor English
//sorry for my poor English
posted @ 2021-03-01 17:33  皮皮刘  阅读(84)  评论(0编辑  收藏  举报