HDU 1255(扫描线、线段树区间修改)
题意
在二维平面坐标轴上输入n个矩形,问被这n个矩形覆盖了两次或两次以上的区域的面积总和。
给的题意有点问题,实际输入是矩形的左下和右上,另外样例1应该输出7.62.
思路
扫描线,这里是沿着x轴正方向每次用一条垂直于x轴的直线去扫,离散化y坐标的值,用线段树维护y坐标上合法区间的和。注意,我们线段树实际要维护的是y坐标间的线段长度,注意到n个点组成的n-1个线段区间,需要将[0,n]的下标转化为[1,n-1]的线段树所管理的区间上,之后再维护线段树。用c1表示被覆盖了1次的区间,c2表示被覆盖了2次的区间。其余就是线段树通用操作了。
1 #define IO std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) 2 #define bug(x) cout<<#x<<" is "<<x<<endl; 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdio> 6 #include<vector> 7 #include<tuple> 8 #define rs o*2+1 9 #define ls o*2 10 using namespace std; 11 const int N=1e4+5; 12 int T, n, add[N*4]; 13 double c1[N*4], c2[N*4]; 14 vector <tuple<double, double, double, int>> v; 15 vector <double> id; 16 void push_up(int o, int l, int r){ 17 if (add[o] >= 2) c2[o] = id[r]-id[l-1]; 18 else if (add[o] == 1) c2[o] = c1[ls] + c1[rs]; 19 else if (r != l) c2[o] = c2[ls] +c2[rs]; 20 else c2[o] = 0; 21 if (add[o]) c1[o] = id[r]-id[l-1]; 22 else if (r != l) c1[o] = c1[ls] +c1[rs]; 23 else c1[o] = 0; 24 } 25 void up(int o, int l, int r, int ql, int qr, int d){ 26 if (l >= ql && r <= qr){ 27 add[o] += d; 28 push_up(o, l, r); 29 return; 30 } 31 int m = (l+r)/2; 32 if (ql <= m) up(ls, l, m, ql, qr, d); 33 if (qr > m) up(rs, m+1, r, ql, qr, d); 34 push_up(o, l, r); 35 } 36 int gao(double x){ 37 return lower_bound(id.begin(), id.end(), x)-id.begin(); 38 } 39 int main(){ 40 IO; 41 cin >> T; 42 while (T--){ 43 cin >> n; 44 double l, r, d, u; 45 id.clear(); 46 v.clear(); 47 for (int i = 0; i < n; i++){ 48 cin >> l >> d >> r >> u; 49 id.push_back(d); 50 id.push_back(u); 51 v.push_back(make_tuple(l, d, u, 1)); 52 v.push_back(make_tuple(r, d, u, -1)); 53 } 54 sort(id.begin(), id.end()); 55 id.erase(unique(id.begin(), id.end()), id.end()); 56 sort(v.begin(), v.end()); 57 double pre = 0, ans = 0; 58 for (auto i:v){ 59 double pos = get<0>(i), d = get<1>(i), u = get<2>(i); 60 int del = get<3>(i); 61 ans += (pos-pre)*c2[1]; 62 pre = pos; 63 up(1, 1, id.size()-1, gao(d)+1, gao(u), del); 64 } 65 printf("%.2f\n", ans); 66 } 67 }