给出n个矩形的左下角和右上角的坐标,求矩形面积的并。
矩形面积并指的是被矩形覆盖到的面积和,重叠部分仅算一次。
多组输入,每组首先一个整数 n,代表矩形的数量;
接下来每行四个整数 x1,x2,y1,y2,表示左上角坐标(x1,y1)与右下角(x2,y2)
每行一个整数,表示矩形的面积并。
input
1
0 0 10 10
2
0 0 10 10
5 5 6 6
0
output
100
100
1 ≤ \leq ≤ n ≤ \leq ≤ 1e5
1 ≤ \leq ≤ x1 < < < x2 ≤ \leq ≤ 1e5
1 ≤ \leq ≤ y1 < < < y2 ≤ \leq ≤ 1e5
Time limit:2000 ms
Memory limit: 256 MB
https://acm.uestc.edu.cn/problem/bai-gei-de-ji-he-ti-1/description
很容易发现,这个题目就是把一维的区间覆盖问题变成了二维的矩形覆盖问题。
一维的区间覆盖问题就是裸的线段树问题,所以刚拿到这题的我就以为是一个裸的二维线段树问题。然而,看到数据范围,我就傻了,二维线段树的空间复杂度是V( N 2 N^2 N2 ), 所以可以直接否决二维线段树了。
但是这个数据范围告诉我们基本可以确定是线段树了,但我们只能对其中一个维度进行线段树维护。矩形面积不是等于长*宽吗,我们用线段树维护了长度,再乘以一个高就是面积了。
还是看图理解吧。。。
我们可以根据每条横边的高度,将图形分块
我们可以根据矩形上下边界的高度将图形分为若干块,用每块的高度乘上这块的区间覆盖长度就是这一块的面积。这个区间覆盖长度就是一维的线段树问题。从上往下计算时,上边界加,下边界减。
1.读入每个矩形的两个角坐标
2.将矩形上下边界的左右端点位置、高度、类型(上边界or下边界)信息存入
3.对这2n条线段按高度排序
4.扫描每条线段,对线段树进行修改,修改后查询覆盖区间长度
5.统计答案 ans+=len*high;
每次修改的时间复杂度为O( l o g ( R − L ) \ log(R-L) log(R−L))
每次查询的时间复杂度为O( l o g ( R − L ) \ log(R-L) log(R−L))
R为右边界,L为左边界,R-L是 1 0 5 10^5 105级别
总的时间复杂度为O(N l o g N logN logN)
#include
#include
#include
#include
#include
#include
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define ls node<<1
#define rs node<<1|1
#define LL long long
using namespace std;
const int maxx=1e5+10;
int read(){
char x=getchar(); int u=0,fg=0;
while(!isdigit(x)){ if(x=='-') fg=1; x=getchar(); }
while(isdigit(x)){ u=(u<<3)+(u<<1)+(x^48); x=getchar(); }
return fg?-u:u;
}
struct segment{
int l,r,h;
bool up;
bool operator <(const segment tmp)const{
return h<tmp.h;
}
}s[maxx<<1];
int tr[maxx<<2],lazy[maxx<<2];
int n,cnt,L,R;
void tag(int node,int l,int r,bool add){
if(add){
++lazy[node];
++tr[node];
}
else{
--lazy[node];
--tr[node];
}
}
void push_up(int node){
tr[node]=min(tr[ls],tr[rs]);
}
void push_down(int node,int l,int r,int mid){
if(!lazy[node]) return;
int x=lazy[node];
lazy[ls]+=x;
lazy[rs]+=x;
tr[ls]+=x;
tr[rs]+=x;
lazy[node]=0;
}
void update(int node,int l,int r,int x,int y,bool add){
if(x<=l && y>=r){
tag(node,l,r,add);
return ;
}
if(l>=r) return ;
int mid=(l+r)>>1;
push_down(node,l,r,mid);
if(mid>=y) update(ls,l,mid,x,y,add);
else if(x>mid) update(rs,mid+1,r,x,y,add);
else {
update(ls,l,mid,x,mid,add);
update(rs,mid+1,r,mid+1,y,add);
}
push_up(node);
}
LL query(int node,int l,int r){
if(tr[node]) return r-l+1;
if(l>=r) return 0;
int mid=(l+r)>>1;
push_down(node,l,r,mid);
return query(ls,l,mid)+query(rs,mid+1,r);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
freopen("output.out", "w", stdout);
#endif
int a,b,c,d;
LL ans,len,high;
while(1){
n=read(); cnt=0; L=maxx; R=-maxx;
if(!n) break;
while(n--){
a=read()+1; b=read(); c=read(); d=read();
if(a>c) swap(a,c); //原题数据有点问题,这里进行些处理
if(b>d) swap(b,d);
s[cnt].l=s[cnt|1].l=a;
s[cnt].h=b;
s[cnt].r=s[cnt|1].r=c;
s[cnt|1].h=d;
s[cnt].up=1;
s[cnt|1].up=0;
L=min(L,a);
R=max(R,c);
cnt+=2;
}
sort(s,s+cnt);
update(1,L,R,s[0].l,s[0].r,s[0].up);
len=query(1,L,R); ans=0;
For(i,1,cnt-1){
high=s[i].h-s[i-1].h;
if(high) ans+=len*high;
update(1,L,R,s[i].l,s[i].r,s[i].up);
len=query(1,L,R);
}
printf("%lld\n",ans);
}
return 0;
}