• 求出被矩形覆盖过至少两次的区域的面积(扫描线 + 线段树)


    题目链接:https://vjudge.net/contest/332656#problem/J

    思路:

    这道题的大体的思路其实还是扫描线的思路。 就是我们要清晰之前我们所说的len 代表的是被覆盖了一次及以上次数的线段长度

    为叙述方便,我们假设len[2]为当前线段被覆盖了两次的长度,len[1]为当前线段被覆盖了一次的长度,而len[0]就是这条线段的长度,并且满足len[2]+len[1]=len[0]。

           首先,如果当前这条线段已经被覆盖了两次了,那么这条线段的len[2]就应该等于len[0],而len[1]就应该等于0。

           其次,如果当前这条线段被覆盖了一次,那么这条线段的len[2]就应该是,左右子线段的len[2]的和加上左右子线段的len[1],当然,前提是当前线段不能是线段树中的叶子结点,否则它就没有左右子线段不是吗?这时候,当前线段的len[2]就应该等于0。而len[1]就等于len[0],最后要注意当前线段的len[1]要减去len[2],以满足len[1]+len[2]=len[0]。

           最后,如果这条线段没有被覆盖过,并且当前线段不是线段树里的叶子结点,那么它的len[1]和len[2]都应该从它的左右子线段的len[1]和len[2]得到,如果是叶子结点,那么len[1]和len[2]都等0。

    因为采用的是魔改的线段树 所以叶子结点需要多开一个标记

      1 #include <math.h>
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <iostream>
      5 #include <algorithm>
      6 #include <string>
      7 #include <string.h>
      8 #include <vector>
      9 #include <map>
     10 #include <stack>
     11 #include <set>
     12 #include <random>
     13 
     14 #define LL long long
     15 #define ls nod<<1
     16 #define rs (nod<<1)+1
     17 const int maxn = 2e5 + 10;
     18 const double eps = 1e-9;
     19 
     20 double v[maxn];
     21 
     22 struct L {
     23     double x;
     24     double y1,y2;
     25     int state;
     26     bool operator <(const L &ith) const{
     27         return x<ith.x;
     28     }
     29 }line[maxn];
     30 
     31 struct segment_tree {
     32     double l,r;
     33     int cover;
     34     double len[3];
     35     bool flag;
     36     void init() {
     37         memset(len,0, sizeof(len));
     38     }
     39 }tree[maxn<<3];
     40 
     41 void pushup(int nod) {
     42     if (tree[nod].cover) {
     43         tree[nod].len[0] = tree[nod].r - tree[nod].l;
     44     }
     45     else
     46         tree[nod].len[0] = tree[ls].len[0] + tree[rs].len[0];
     47 
     48     if (tree[nod].cover >= 2) {
     49         tree[nod].len[2] = tree[nod].len[0];
     50         tree[nod].len[1] = 0;
     51     }
     52     else if (tree[nod].cover == 1) {
     53         if (tree[nod].flag) {
     54             tree[nod].len[2] = 0;
     55         }
     56         else {
     57             tree[nod].len[2] = (tree[ls].len[2] + tree[rs].len[2] + tree[ls].len[1] + tree[rs].len[1]);
     58         }
     59         tree[nod].len[1] = tree[nod].len[0];
     60         tree[nod].len[1] -= tree[nod].len[2];
     61     }
     62     else {
     63         if (tree[nod].flag) {
     64             tree[nod].len[2] = tree[nod].len[1] = 0;
     65         }
     66         else {
     67             tree[nod].len[2] = tree[ls].len[2] + tree[rs].len[2];
     68             tree[nod].len[1] = tree[ls].len[1] + tree[rs].len[1];
     69         }
     70     }
     71 }
     72 
     73 void build(int l,int r,int nod=1) {
     74     tree[nod].l = v[l];
     75     tree[nod].r = v[r];
     76     tree[nod].init();
     77     tree[nod].cover = 0;
     78     tree[nod].flag = false;
     79     if (r-l <= 1) {
     80         tree[nod].flag = true;
     81         return;
     82     }
     83     int mid = (l + r) >>  1;
     84     build(l,mid,ls);
     85     build(mid,r,rs);
     86 }
     87 
     88 void modify(double x,double y,int z,int nod=1) {
     89     double l = tree[nod].l,r = tree[nod].r;
     90     if (x <= l && y >= r){
     91         tree[nod].cover += z;
     92         pushup(nod);
     93         return ;
     94     }
     95     if (x < tree[ls].r)
     96         modify(x,y,z,ls);
     97     if (y > tree[rs].l)
     98         modify(x,y,z,rs);
     99     pushup(nod);
    100 }
    101 
    102 int main() {
    103     int T;
    104     scanf("%d",&T);
    105     while (T--) {
    106         int n;
    107         double a, b, c, d;
    108         scanf("%d",&n);
    109         for (int i = 1; i <= n; i++) {
    110             scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
    111             v[i] = b;
    112             v[n + i] = d;
    113             line[i].x = a;
    114             line[i].y1 = b;
    115             line[i].y2 = d;
    116             line[i].state = 1;
    117             line[i+n].x = c;
    118             line[i+n].y1 = b;
    119             line[i+n].y2 = d;
    120             line[i+n].state = -1;
    121         }
    122         std::sort(v + 1, v + 1 + (n << 1));
    123         std::sort(line + 1, line + 1 + (n << 1));
    124         build(1, n << 1);
    125         double ans = 0.0;
    126         for (int i = 1; i <= 2 * n; i++) {
    127             ans += tree[1].len[2] *(line[i].x - line[i-1].x);
    128             //printf("%lf
    ",tree[1].len[2]);
    129             modify(line[i].y1, line[i].y2, line[i].state);
    130         }
    131         printf("%.2lf
    ",ans);
    132     }
    133     return 0;
    134 }
  • 相关阅读:
    windows2019开发windows服务
    vue开发笔记
    kafka管理界面 kafka eagle
    WPF 无边框窗体改变大小和移动
    3种方法改变Linux的默认shell
    Linux,原来cd命令这样玩
    Linux中cp命令的使用方法
    Linux 中ls命令的使用
    如何查看Linux的内存使用率
    Linux中如何重命名文件
  • 原文地址:https://www.cnblogs.com/-Ackerman/p/11734737.html
Copyright © 2020-2023  润新知