zoukankan      html  css  js  c++  java
  • 线段树扫描线总结(POJ 1389)

    扫描线算是线段树的一个比较特殊的用法,虽然NOIP不一定会考,但是学学还是有用的,况且也不是很难理解。

    以前学过一点,不是很透,今天算是搞懂了。

    就以这道题为例吧:嘟嘟嘟

    题目的意思是在一个二维坐标系中给了很多矩形,然后求这些矩形的总覆盖面积,也就是面积并。

    我就不讲暴力,直接切入正题吧。

     

    扫描线,听这个名字就可以想象一下,现在有这么多重叠的矩形,然后有一个线从下往上扫,那么每一时刻这条线上被覆盖的长度之和,就是我们要求的答案。

    那么首先可以想到,要把给定的矩形都离线下来,拆成上下来个面,并标记这个矩形从哪开始,从哪结束,最后按x(或y)排好序。

    上面的可以算作预处理,接下来才是重点:怎么用线段树维护这个扫描线的覆盖问题?

    首先要清楚的是,这并不是单纯的区间覆盖,因为区间覆盖的清空是把这个区间都清零,但是在对于扫线上的一段区间的清空,实际上只是清空了这一层,而他下面那一层应该还保持原样。这该怎么实现呢? 

    首先需要一个cov标记,表示这个区间被覆盖了几层,那么一个矩形的开始就是多覆盖一层,结束就是减去一层。由此可知,如果cov > 1的话,那么这个区间就全被覆盖了,sum就等于区间长度;那么cov = 0呢?说明这个区间只有一部分被覆盖,sum[now] = sum[now <<1] +sum[now <<1 | 1]。这是为什么就等于左右子区间的和呢?想一下,我们更新的时候,要是更新区间和当前区间一样的话,就停止了,那么他的子区间还是保持了原来的情况。因此我们掀开了这一层,露出来的就是他的子区间那没有被完全覆盖的情况。因此sum[now] = sum[now << 1] +sum[now <<1 | 1].

    还有一点,那就是cov永远不会小于0,因为cov--的条件是有一个矩形结束了,那有结束必定有开始,所以一定是先加后减。但有人又会问,如果是别的矩形改变了这个区间的cov值呢?那也同理,也是先加后减。所以cov永远是大于0的。

    pushup也一样,cov大于0,则sum就是区间长度,否则是左右子区间的和。

    (懒得画图……)

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<cctype>
      8 #include<vector>
      9 #include<stack>
     10 #include<queue>
     11 using namespace std;
     12 #define enter puts("") 
     13 #define space putchar(' ')
     14 #define Mem(a, x) memset(a, x, sizeof(a))
     15 #define rg register
     16 typedef long long ll;
     17 typedef double db;
     18 const int INF = 0x3f3f3f3f;
     19 const db eps = 1e-8;
     20 const int maxn = 5e4 + 5;
     21 inline ll read()
     22 {
     23   ll ans = 0;
     24   char ch = getchar(), last = ' ';
     25   while(!isdigit(ch)) {last = ch; ch = getchar();}
     26   while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
     27   if(last == '-') ans = -ans;
     28   return ans;
     29 }
     30 inline void write(ll x)
     31 {
     32   if(x < 0) x = -x, putchar('-');
     33   if(x >= 10) write(x / 10);
     34   putchar(x % 10 + '0');
     35 }
     36 
     37 int xl, yl, xr, yr, cnt = 1;
     38 struct Node
     39 {
     40   int L, R, h, flg;
     41   bool operator < (const Node &oth)const
     42   {
     43     return h < oth.h;
     44   }
     45 }a[maxn << 1];
     46 
     47 int l[maxn << 2], r[maxn << 2], sum[maxn << 2], cov[maxn << 2];
     48 void build(int L, int R, int now)
     49 {
     50   sum[now] = cov[now] = 0;
     51   l[now] = L; r[now] = R;
     52   if(L == R) return;
     53   int mid = (L + R) >> 1;
     54   build(L, mid, now << 1);
     55   build(mid + 1, R, now << 1 | 1);
     56 }
     57 void update(int L, int R, int flg, int now)
     58 {
     59   if(L == l[now] && R == r[now])
     60     {
     61       cov[now] += flg;
     62       if(cov[now]) sum[now] = R - L + 1;
     63       else
     64     {
     65       if(L == R) sum[now] = 0;        //别忘判断叶子节点 
     66       else sum[now] = sum[now << 1] + sum[now << 1 | 1];
     67     }
     68       return;
     69     }
     70   int mid = (l[now] + r[now]) >> 1;
     71   if(R <= mid) update(L, R, flg, now << 1);
     72   else if(L > mid) update(L, R, flg, now << 1 | 1);
     73   else update(L, mid, flg, now << 1), update(mid + 1, R, flg, now << 1 | 1);
     74   if(cov[now]) sum[now] = r[now] - l[now] + 1;
     75   else sum[now] = sum[now << 1] + sum[now << 1 | 1];
     76 }
     77 
     78 int solve()
     79 {
     80   build(1, maxn - 1, 1);
     81   ll ans = 0;
     82   sort(a + 1, a + cnt + 1);
     83   for(int i = 1; i <= cnt; ++i)
     84     {
     85       update(a[i].L, a[i].R, a[i].flg, 1);
     86       ans += sum[1] * (a[i + 1].h - a[i].h);
     87     }
     88   return ans;
     89 }
     90 
     91 int main()
     92 {
     93   while(1)
     94     {
     95       cnt = 0;
     96       bool flg = 0;
     97       while(1)
     98     {
     99       xl = read() + 1; yl = read() + 1; xr = read(); yr = read() + 1;
    100       if(!xl && !flg) return 0;
    101       else if(!xl) break;
    102       else
    103         {
    104           a[++cnt] = (Node){xl, xr, yl, 1};
    105           a[++cnt] = (Node){xl, xr, yr, -1};
    106           flg = 1;
    107         }
    108     }
    109       write(solve()); enter;
    110     }
    111   return 0;
    112 }
    View Code
  • 相关阅读:
    openmp 循环并行化循环嵌套内部无法并行
    c++:strcat潜在的错误不报告
    script php / phpfpm /
    webserver waf / WAF 2.0 / ASERVER/1.2.9
    web test LoadRunner FTP / vsftpd / vsftp / WebUploader 0.1.5 / shangchuan
    my ReadTravel_Singapore / singapore / xinjiapo / lvyou / travel
    OS Security var_log_secure / services / port
    EF操作数据库的步骤和一些简单操作语句
    (大快人心,必须转啊)中国体操男队完美逆转卫冕 日本申诉成功获银牌
    [置顶] 【C/C++学习】之一、指针和引用的区别
  • 原文地址:https://www.cnblogs.com/mrclr/p/9781358.html
Copyright © 2011-2022 走看看