题解:SP17123 IMBOX - Destroying the Weapon Warehouse

扫描线模板题。

双倍经验

这题是最基础的矩形面积并题目。

像这样,把多个相交矩形转化成不相交的矩形面积和。

这些矩形的高很简单,所以我们现在考虑怎么计算长。

这时我们需要引入“入边”和“出边”的概念。

定义:在同一个矩形内,从下往上看,第一条看到的边为“入边”,第二条看到的边为“出边”。

图片来自OI WiKi

从下往上,就是扫描线的方向。
当从下往上扫,遇到入边的线,则对入边区间扫到进行 \(+1\) 操作,遇到出边,那么对出边区间进行 \(-1\) 操作。

将上述的模型转成线段树就可以了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int ls(int p){
	return p<<1;
}
int rs(int p){
	return p<<1|1;
}
const int N=8000005;
int Tag[N];   
int length[N]; 
int xx[N]; 
struct ScanLine{
	int y;
	int right_x,left_x;
	int inout;
	ScanLine(){}
	ScanLine(int y,int x2,int x1,int io):
		y(y),right_x(x2),left_x(x1),inout(io){}
} line[N];
bool cmp(ScanLine &a,ScanLine &b){
	return a.y<b.y;
}
void pushup(int p,int pl,int pr){  
	if(Tag[p])    length[p]=xx[pr]-xx[pl];
	else if(pl+1 == pr)  length[p]=0;
	else length[p]=length[ls(p)] + length[rs(p)];
}
void update(int L,int R,int io,int p,int pl,int pr){
	if(L<=pl && pr<=R){
		Tag[p] += io; 
		pushup(p,pl,pr);
		return;
	}
	if(pl+1 == pr)  return;
	int mid=(pl+pr) >> 1;
	if(L<=mid)  update(L,R,io,ls(p),pl,mid);
	if(R>mid)   update(L,R,io,rs(p),mid,pr);
	pushup(p,pl,pr);
}
signed main(){
	int n;
	cin>>n;
	int cnt=0; 
	while(n--){
		int x1,x2,y1,y2;
		cin>>x1>>y1>>x2>>y2;
		line[++cnt]=ScanLine(y1,x2,x1,1);
		xx[cnt]=x1;
		line[++cnt]=ScanLine(y2,x2,x1,-1);
		xx[cnt]=x2;      
	}
	sort(xx+1,xx+cnt+1);
	sort(line+1,line+cnt+1,cmp);
	int num=unique(xx+1,xx+cnt+1)-(xx+1);
	memset(Tag,0,sizeof(Tag));
	memset(length,0,sizeof(length));
	int ans=0;
	for(int i=1;i<=cnt;++i){
		int L,R;
		ans += length[1]*(line[i].y-line[i-1].y);
		L=lower_bound(xx+1,xx+num+1,line[i].left_x)-xx;
		R=lower_bound(xx+1,xx+num+1,line[i].right_x)-xx;
		update(L,R,line[i].inout,1,1,num);
	}
	cout<<ans<<endl;
	return 0;
}

posted @ 2024-09-16 11:31  cly312  阅读(9)  评论(0)    收藏  举报