首页 > 代码库 > HDU 1255 覆盖的面积 ——(线段树+扫描线)

HDU 1255 覆盖的面积 ——(线段树+扫描线)

  又做了一题扫描线以后对节点的覆盖标记理解的更加深刻了。

  代码如下:

  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 }

 

HDU 1255 覆盖的面积 ——(线段树+扫描线)