算法学习——————扫描线

回顾才发现扫描线还没有写过

解决问题:矩形的面积并,周长并问题

思想:利用分割法求矩形的面积

做法:

规定:从下往上扫

  1. 首先对纵坐标进行排序

问题:范围很大

  1. 离散化(注意求面积的时候不能用离散化后的坐标)

整体过程:遇下边加边,遇上边减边,切割出的矩形面积就是当前线段长度\(\times\)两次修改间的高度

  1. 下边权值设为1,上边权值设为1,加入到线段树内

维护信息(暂):区间内的线段长度

问题是,删除一条线段的时候可能区间线段长度不变,因为可能有多条线段有重合

  1. lazy表示区间被几条线段完整覆盖,tree表示区间内的线段长度,若lazy > 0,tree = 区间长度,否则tree = tree[ls] + tree[rs]

最后一个问题,我也有很多的疑问,举个别人题解里的例子

比如离散化后有四个X,我们一次修改要修改离散化后1-3(原X1-X3),模拟在线段树的过程,我们会分别走到1-2和3-3两个区间,第一个区间没有问题tree = X2-X1,那么第二个区间呢?tree = X3-X3 = 0 ?显然是错误的

  1. 那么在这里我们的做法就是修改定义,让线段树对应的l-r区间改为l-r+1区间,这样就保证了长度为len的区间能被分成len个单位区间,修改区间l-r的时候只要修改l-r-1就可以了

最后因为询问整个线段树,所以不需要pushdown

顺便在写代码的时候还发现几个问题

  1. 最后一次不需要修改,因为一定是上边,对答案没有价值,而且没有line[i+1]

  2. 数组大小

code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define O(x) cout<<#x<<" "<<x<<endl;
#define B cout<<"Breakpoint"<<endl;
#define ll long long
using namespace std;
ll read(){
	ll x = 1,a = 0;char ch = getchar();
	while (ch < '0'||ch > '9'){if (ch == '-') x = -1;ch = getchar();}
	while (ch >= '0'&&ch <= '9'){a = a*10+ch-'0';ch = getchar();}
	return x*a;
}
const int maxn = 4e5+10; 
int n;
struct node{
	int l,r,high,op;
}line[maxn << 1];
bool cmp(node x,node y){
	return x.high < y.high;
}
ll cnt,X[maxn << 1];
ll tree[maxn << 2],lazy[maxn << 2];
ll ls(int x){return x << 1;}
ll rs(int x){return x << 1|1;}
void pushup(int x,int l,int r){
	if (lazy[x]) tree[x] = X[r+1]-X[l];
	else tree[x] = tree[ls(x)] + tree[rs(x)];
}
void modify(int x,int l,int r,int nl,int nr,int v){
	if (nl <= X[l]&&X[r+1] <= nr){
		lazy[x] += v;pushup(x,l,r);
		return;
	}
	int mid = (l+r) >> 1;
	if (nl <= X[mid]) modify(ls(x),l,mid,nl,nr,v);
	if (nr > X[mid+1]) modify(rs(x),mid+1,r,nl,nr,v);
	pushup(x,l,r);
}
ll ans;
int main(){
	n = read();
	for (int i = 1;i <= n;i++){
		ll x_1,x_2,y_1,y_2;
		x_1 = read(),y_1 = read(),x_2 = read(),y_2 = read();
		line[++cnt] = (node){x_1,x_2,y_1,1},X[cnt] = x_1;
		line[++cnt] = (node){x_1,x_2,y_2,-1},X[cnt] = x_2;
	}
	sort(line+1,line+cnt+1,cmp);
	sort(X+1,X+cnt+1);
	int tot = unique(X+1,X+cnt+1)-X-1;
	for (int i = 1;i < cnt;i++){
		modify(1,1,tot-1,line[i].l,line[i].r,line[i].op);
		ans += tree[1]*(line[i+1].high-line[i].high);
	}
	cout<<ans<<endl;
	return 0;
} 

还算简便??怎么会有人说我代码可读性差

posted @ 2022-08-26 11:20  小又又yyyy  阅读(40)  评论(0编辑  收藏  举报