又做了一题扫描线以后对节点的覆盖标记理解的更加深刻了。
代码如下:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #define t_mid (l+r>>1) 5 #define ls (o<<1) 6 #define rs (o<<1|1) 7 #define lson ls,l,t_mid 8 #define rson rs,t_mid+1,r 9 using namespace std; 10 const int N = 1000 + 5; 11 const int MAX = N * 2; 12 const double eps = 1e-6; 13 14 struct seg 15 { 16 double x1,x2,y; 17 int d; 18 bool operator < (const seg & temp) const 19 { 20 return std::fabs(y-temp.y) <= eps ? d > temp.d : y < temp.y; 21 } 22 }g[N<<1]; 23 int n,tot,ptot; 24 int lazy[MAX<<2]; 25 double pos[MAX],c[MAX<<2],cc[MAX<<2]; 26 void add(double x1,double x2,double y,int d) 27 { 28 tot++; 29 g[tot] = {x1,x2,y,d}; 30 } 31 void read() 32 { 33 tot = ptot = 0; 34 scanf("%d",&n); 35 for(int i=1;i<=n;i++) 36 { 37 double x1,y1,x2,y2; 38 scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); 39 add(x1,x2,y1,1); 40 add(x1,x2,y2,-1); 41 pos[++ptot] = x1; 42 pos[++ptot] = x2; 43 } 44 sort(g+1,g+1+tot); 45 sort(pos+1,pos+1+ptot); 46 int m = 1; 47 for(int i=2;i<=ptot;i++) 48 { 49 if(std::fabs(pos[i]-pos[i-1]) > eps) 50 { 51 pos[++m] = pos[i]; 52 } 53 } 54 ptot = m; 55 } 56 57 int Find(double x) 58 { 59 int L = 1, R = ptot; 60 while(L <= R) 61 { 62 int mid = L + R >> 1; 63 if(std::fabs(pos[mid]-x) <= eps) return mid; 64 else if(pos[mid] < x) L = mid + 1; 65 else R = mid - 1; 66 } 67 return -1; 68 } 69 70 void pushup(int o,int l,int r) 71 { 72 if(lazy[o] > 0) c[o] = pos[r] - pos[l-1]; 73 else if(l == r) c[o] = 0; 74 else c[o] = c[ls] + c[rs]; 75 /*************************/ 76 if(lazy[o] >= 2) cc[o] = pos[r] - pos[l-1]; 77 else if(l == r) cc[o] = 0; 78 else if(lazy[o] == 1) cc[o] = c[ls] + c[rs]; 79 else cc[o] = cc[ls] + cc[rs]; 80 } 81 82 void update(int o,int l,int r,int ql,int qr,int f) 83 { 84 if(ql == l && qr == r) 85 { 86 lazy[o] += f; 87 pushup(o,l,r); 88 return ; 89 } 90 if(qr <= t_mid) update(lson,ql,qr,f); 91 else if(ql > t_mid) update(rson,ql,qr,f); 92 else 93 { 94 update(lson,ql,t_mid,f); 95 update(rson,t_mid+1,qr,f); 96 } 97 pushup(o,l,r); 98 } 99 100 void solve() 101 { 102 memset(lazy,0,sizeof(lazy)); 103 memset(c,0,sizeof(c)); 104 memset(cc,0,sizeof(cc)); 105 double ans = 0; 106 for(int i=1;i<=tot;) 107 { 108 int j = i; 109 while(j <= tot && std::fabs(g[i].y-g[j].y) <= eps) 110 { 111 int L = Find(g[j].x1); 112 int R = Find(g[j].x2); 113 /* 114 下面的L要加1是因为两个点重合但是其实线段是不重合的, 115 所以线段树内不能让他们管辖同一块地方 116 而pushup里面再L减1是因为,计算两点之间的距离要用原来的点算 117 */ 118 update(1,0,MAX,L+1, R, g[j].d); 119 j++; 120 } 121 if(j <= tot) ans += 1.0*(g[j].y-g[i].y) * cc[1]; 122 i = j; 123 } 124 printf("%.2f\n",ans); 125 } 126 127 int main() 128 { 129 int T; 130 scanf("%d",&T); 131 while(T--) 132 { 133 read(); 134 solve(); 135 } 136 return 0; 137 }