zoukankan      html  css  js  c++  java
  • 线段树扫描线(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 上有值的话,那么表示 这个区间被完全覆盖的。 

    如果区间A被完全覆盖了, 那么会在区间A对应的cnt++, 然后 进行更新和返回(return;)

    但是由于不下推, 所以A的左子树或者右子树上的cnt都不会发生变化。所以,如果A的左子树或右子树上

    的cnt不为0,那么一定有另一条线扫描到了左子树或者右子数,并且没有完全覆盖区间A。

    所以,如果A的cnt == 1并且 A的子树上有值,那么子树上的线段长度和就是至少访问过2次的线段长度和了);

    当然 如果 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 }
  • 相关阅读:
    android 如何添加第3方lib库到kernel中
    如何搭建modem编译环境
    /dev、/sys/dev 和/sys/devices 和udev的关系
    Makefile的obj-y 和 obj-m
    MTK Android添加驱动模块
    使用 /sys 文件系统访问 Linux 内核
    JNI设置C++与java的结合(2)
    android 常用方法集合
    操作系统(科普章节)
    前端面试之前要准备的那些事
  • 原文地址:https://www.cnblogs.com/MingSD/p/8393274.html
Copyright © 2011-2022 走看看