线段树扫描线(2---算矩形的相交面积)

Posted Schenker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树扫描线(2---算矩形的相交面积)相关的知识,希望对你有一定的参考价值。

HDU-1255

首先感谢一下 Titanium:http://acm.hdu.edu.cn/showproblem.php?pid=1255

怎么计算出重复的面积。

遇到这个求相交矩形的面积的时候,我第一反应就是将cnt标记下推,然后每次都将标记下推, 最后根据cnt的值来模仿1中求面积的方式来求,然后实现起来很复杂,并且估计会超时,所以就百度寻求了一波帮助。

我们先规定sum2 为 至少出现1次时统计的长度 sum为至少出现2次时的长度

如果某个区间的cnt >= 2 那么 就表示这个这个区间的所有长度都是有效长度, sum就等于这个区间的总长度

当cnt == 1时, 表示这整个区间线段至少出现过一次  并且这个区间内的部分线段会出现好多次 

这个时候访问这个节点的左子树和右子树sum2,sum = sum2(左子树)+sum2(右子树)。

因为这个区间的cnt == 1 表示这个区间的长度都至少出现过了一次, 由于是区间更新且没有下推cnt 

如果左子树和右子树上sum2 != 0, 那么表示在左子树和右子树上又出现了一次。

(请读者充分理解线段树的区域更新, 如果cnt 上有值的话,那么表示 这个区间被完全覆盖的。 )

当然 如果 l==r的时候有效长度还是为0的, 因为叶子节点没有长度。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<iomanip>
 4 #define lson l,m,rt<<1
 5 #define rson m+1,r,rt<<1|1
 6 using namespace std;
 7 const int N = 1e4;
 8 struct Node
 9 {
10     double l, r, h;
11     int d;
12     bool operator < (const Node & x) const
13     {
14         return h < x.h;
15     }
16 }A[N];
17 double X[N], sum[N], sum2[N];
18 int cnt[N];
19 void Build(int l, int r, int rt)
20 {
21     sum2[rt] = 0.0,cnt[rt] = 0, sum[rt] = 0.0;
22     if(l == r) return ;
23     int m = l+r >> 1;
24     Build(lson);
25     Build(rson);
26 }
27 void PushUp(int l, int r, int rt)
28 {
29     if(cnt[rt])
30     {
31         sum2[rt] = X[r] - X[l-1];
32     }
33     else if(l == r) sum2[rt] = 0.0;
34     else sum2[rt] = sum2[rt<<1] + sum2[rt<<1|1];
35     if(cnt[rt] > 1)
36         sum[rt] = X[r] - X[l-1];
37     else if(l == r) sum[rt] = 0;
38     else if(cnt[rt] == 1) sum[rt] = sum2[rt<<1]+sum2[rt<<1|1];
39     else sum[rt] = sum[rt<<1] + sum[rt<<1|1];
40 }
41 void Revise(int L, int R, int C, int l, int r, int rt)
42 {
43     if(L <= l && r <= R)
44     {
45         cnt[rt] += C;
46         PushUp(l,r,rt);
47         return ;
48     }
49     int m = l+r >> 1;
50     if(L <=m) Revise(L,R,C,lson);
51     if(m < R) Revise(L,R,C,rson);
52     PushUp(l,r,rt);
53 }
54 void Add(double l, double r, double h, int d, int i)
55 {
56     A[i].l = l; A[i].h = h;
57     A[i].r = r; A[i].d = d;
58 }
59 int main()
60 {
61     ios::sync_with_stdio(false);
62     cin.tie(0);
63     cout.tie(0);
64     int T, n;
65     cin >> T;
66     while(T-- && cin >> n)
67     {
68         int k = 0;
69         double x1, y1, x2, y2;
70         for(int i = 1; i <= n; i++)
71         {
72             cin >> x1 >> y1 >> x2 >> y2;
73             Add(x1,x2,y1,1,k);
74             X[k++] = x1;
75             Add(x1,x2,y2,-1,k);
76             X[k++] = x2;
77         }
78         sort(X,X+k);
79         sort(A,A+k);
80         int pos = 1;
81         for(int i = 1; i < k; i++)
82         {
83             if(X[i] != X[i-1])
84                 X[pos++] = X[i];
85         }
86         Build(1,pos,1);
87         double ans = 0;
88         for(int i = 0; i < k-1; i++)
89         {
90             int l = lower_bound(X,X+pos,A[i].l) - X;
91             int r = lower_bound(X,X+pos,A[i].r) - X;
92             Revise(l+1,r,A[i].d,1,pos,1);
93             ans += (A[i+1].h - A[i].h) * sum[1];
94         }
95         cout << fixed << setprecision(2) << ans+0.0001 << endl;//莫名其妙样例一的时候没有四舍五入上去
96     }                                  //所以补了一点上去就给过了
97     return 0;
98 }

 

以上是关于线段树扫描线(2---算矩形的相交面积)的主要内容,如果未能解决你的问题,请参考以下文章

hdu 1542(线段树+扫描线 求矩形相交面积)

HDU1542 矩形面积并 扫描线段树

线段树+扫描线求矩形面积的并

矩形面积并矩形面积交矩形周长并(线段树扫描线总结)(转载)

线段树 - 矩形的面积并 (扫描线)

求出被矩形覆盖过至少两次的区域的面积(扫描线 + 线段树)