P5490 【模板】扫描线
扫描线主要解决的是几个矩形的面积并问题.
当然也可以用来解决周长并问题 , 不过由于暂时不会就不说了.
比如下面的几个矩形:
我们假设有一条垂直于 x x x 轴的直线从左往右扫描, 下图将它标记为红色. 不难想到可以计算这条直线扫过的面积来得到所有矩形的面积并.
显然这条直线会碰到最左边的垂直于 x x x 轴的边.
把从最左边的垂直于 x x x 轴的边开始到第二条垂直于 x x x 轴的边中间扫过的矩形的面积标记下来.
此时扫过的矩形的面积就是第一条垂直于 x x x 轴的边长度乘上从最左边的垂直于 x x x 轴的边开始到第二条垂直于 x x x 轴的边扫过的距离.
以此类推, 这是扫到第 3 3 3 条垂直于 x x x 轴的边.
新扫过的面积即橙色面积就是前两个垂直于 x x x 轴的边的长度和乘新扫过的距离.
而扫到第三条垂直于 x x x 轴的边的时候我们发现前三条垂直于 x x x 轴的边的纵坐标有重复部分. 这是怎么计算呢?
可以把覆盖的区间标记一遍, 最后看总长度.
扫到黄色区间结束的时候, 我们发现有一条边不用再继续往下算了(就是最下面那条), 然后我们把它删去即可.
其实我们可以在插入一条边的时候把这个边里的点对应的纵坐标加一, 删除的时候减一, 然后可以达到这种效果.
然后我们发现, 我们要一个可以支持区间操作的数据结构, 可以用线段树来维护这条扫描线.
附上扫描结束的几张图:
然后看怎么实现:
首先要知道存什么: 我们想知道的是每一个矩形两条垂直于 x x x 轴的边. 还要标记一下这是左边那条还是右边那条.
那其实只要保存一条边的上端点和下端点的纵坐标及横坐标外加一个标记就够了.
注意有 n n n 个矩形, 就要存 2 n 2n 2n 条边.
int n, lcnt;
//...
struct node1{
long long x, highy, lowy, flag;
}l[200005];
node1 make_node1(long long xx, long long hy, long long ly, long long f){
//构造函数
node1 T;
T.x = xx;
T.highy = hy;
T.lowy = ly;
T.flag = f;
return T;
}
//...
for(int i = 1; i <= n; ++i){
int x_1, x_2, y_1, y_2;
scanf("%d%d%d%d" ,&x_1 ,&y_1 ,&x_2 ,&y_2);
l[++lcnt] = make_node1(x_1, y_2, y_1, 1);
l[++lcnt] = make_node1(x_2, y_2, y_1, -1);
}
别忘了把这些边按 x x x 排序.
但是我们看数据范围:
对于 % 100 \% 100 %100 的数据, 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1≤n≤105 , 0 ≤ x 1 ≤ x 2 ≤ 1 0 9 0 \le x_1 \le x_2 \le 10^9 0≤x1≤x2≤109 , 0 ≤ y 1 ≤ y 2 ≤ 1 0 9 0 \le y_1 \le y_2 \le 10^9 0≤y1≤y2≤109 。
很明显我们如果区间更新的话, 扫描线就要在 [ 0 , 1 0 9 ] [0, 10^9] [0,10