前言
好久没写得这么爽了~
题目
讲解
在我看来,这是一道码农题。
对于每个矩形,我们考虑计算出顺序在它之后(即可能将其覆盖)且没有与它相交的矩形个数,我们将其取名为合法矩形,然后与顺序在它之后的矩形个数比较即可得出答案。
考虑容斥。
对于每个矩形,我们可以将其四条边无限延长,然后整个平面就被分为了 (9) 个格子。对于上下左右四个方向各三个格子统计出有多少个合法矩形,记录下来。
显然四个角的合法矩形被计算了两次,减掉即可。这就是个简单的偏序问题了,使用 ( t cdq) 即可求解。
小优化:在 ( t cdq) 过程中,显然可以使用归并排序优化时间,当然不优化也行,这道题时限很宽。
注意 ( t cdq) 排序时的顺序,求解时的边界问题以及树状数组的清空(因为我都挂过qwq)。
( t cdq) 套树状数组,时间复杂度是 (O(nlog^2n))。
代码
我的代码实现过于冗长,主要是因为四个角打了四个 ( t 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
");
else printf("DA
");
}
return 0;
}
//sorry for my poor English
//sorry for my poor English