线段树之扫描线思路

运用线段树+扫描线方式
可以解决经典的求矩形面积交问题


以HDU_1542 Atlantis 题为例

线段树和扫描线是这么结合的


    线段树统计的是有效区间段的长度 也就是扫描线 当前扫描到的区间段是哪一个
    什么意思 比如当前在哪一个段扫描 那么线段树中的t[1]中的len就是多长
    线段树一般情况下是一个后序遍历先把孩子节点的信息 更新后 再拿孩子节点的信息回来更新自己

    一旦取消这个线段 遇到了出边 那么就把这个点的覆盖情况置空 然后让这个点的信息为左右两个孩子的信息 统计
    如果这个时候左右两个孩子还有边的信息 那么依然会反馈回来 如果没有 那么这个线段就会置零


    总的来说 线段树统计的就是当前扫描时段真正的有效长度是多少
    如何通过线段树去统计?
    以离散化横坐标为例
    线段树每个叶子节点统计的都是我们所有出现过的从小到大的离散化后的x坐标顺序下标
    比如一共出现了10 15 20 25四个x坐标 由于我们离散化的是横坐标 也就是要拿横坐标建树
    也就是这四个点分别对应0 1 2 3 四个点
    把线段树建成了
    那么每次我们扫描到一个线段 就到线段树中去更新这个线段
    什么意思? 就是按照这个线段是出边还是入边
    如果是矩形入边 那么就把这个线段拿到线段树中去 我们不是已经把线段树按照对应x左边建好了吗
    那么现在遇到一个入边 按照我们之前说的线段树需要维护的东西————“当前扫描的线段所在的矩形的有效宽度”
    我们需要让线段树明白现在的有效宽度是不是变化了
    也就是把这个变得起始坐标 结束坐标搞下来 更新到线段树中
    这样我们到时候一查线段树的有效宽度 然后再用高度做一下差
    就知道当前扫描矩形的有效面积是多少了
    那么我们拿到当前边的两个坐标 去线段树中更新
    如果这个区间段在线段树中没有标记过 那么就去标记
    标记后反馈给父节点
    不断的反馈 最后父节点得到了当前状态下的有效宽度

    那么如果当前边是个出边 也就是有可能需要减少

    依然是拿到线段树中 把宽度取消

    当我们遍历了扫描方向上的所有的边 也就是把每一块的面积都累加了起来 

也就是实现了面积统计 复杂度O(edge*logn)
HDU_1542 Atlantis CODE:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 110;
struct node{int xx;double len;int l,r;
}t[maxn<<3];
double x[maxn<<2];
int xtot;
struct edge{double l,r,h;int xx;edge(){}edge(double a,double b,double c,int cover):l(a),r(b),h(c),xx(cover){}bool operator<(const edge &E){return h<E.h;}
}e[maxn<<2];
int etot;
bool cmp(int a,int b){return a<b;
}
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
void build(int l,int r,int rt){t[rt].l = l;t[rt].r = r;t[rt].xx = t[rt].len = 0;if(l==r)return;int mid = l+r>>1;build(lson);build(rson);
}
void pushup(int now){if(t[now].xx){t[now].len = x[t[now].r+1]-x[t[now].l];}else if(t[now].l==t[now].r){t[now].len=0;}else {t[now].len = t[now<<1].len+t[now<<1|1].len;}
}void update(int l,int r,int rt,int val){if(t[rt].l==l&&t[rt].r==r){t[rt].xx += val;pushup(rt);return;}int mid = t[rt].l+t[rt].r>>1;//*****if(r<=mid)update(l,r,rt<<1,val);else if(l>mid)update(l,r,rt<<1|1,val);else{update(l,mid,rt<<1,val);update(mid+1,r,rt<<1|1,val);}pushup(rt);
}
int main()
{int n,test=0;while(scanf("%d",&n),n){double x1,x2,y1,y2;test++;for(int i=1;i<=n;i++){scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);e[etot++] = edge(x1,x2,y1,1);e[etot++] = edge(x1,x2,y2,-1);x[xtot++] = x1;x[xtot++] = x2;}sort(e,e+etot);sort(x,x+xtot);xtot = unique(x,x+xtot)-x;//离散化x坐标double ans =0;build(0,xtot-1,1);for(int i=0;i<etot;i++){int l = lower_bound(x,x+xtot,e[i].l)-x;int r = lower_bound(x,x+xtot,e[i].r)-x-1;//区间这里并不是完全包含比如10,15,20,25 的区间 查询10-15 那么去查的就是10-10//什么意思 因为线段树仍然是离散的统计结构 仍然还是按照起点查询区间线段update(l,r,1,e[i].xx);ans+=(e[i+1].h-e[i].h)*t[1].len;}printf("Test case #%d\nTotal explored area: %.2f\n\n",test,ans);etot = 0;xtot = 0;}return 0;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/425227.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

74 param动作

定义一个logind的jsp <% page language"java" import"java.util.*" contentType"text/html; charsetutf-8"%><!DOCTYPE html> <html> <head> <meta charset"ISO-8859-1"> <title>Insert title h…

Unknown column 'user_uid' in 'field list' sql错误解决过程

在idea中运行一直有错&#xff0c;找了好多个地方都找不到&#xff0c;以为是我的字段名字写错了&#xff0c;然而都是对的。 把错误的这个字段删了再打一遍就好了&#xff0c; 转载于:https://www.cnblogs.com/zxrxzw/p/10630164.html

[密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第9篇]香农对熵和信息的定义是什么?

这是计算机理论的最后一篇.我们讨论信息理论的基础概念,什么是香农定义的熵和信息. 熵 熵与确定性成反比 信息 密码学实例 [1] Thomas M. Cover and Joy A. Thomas. Elements of Information Theory ​ 2nd Edition. Wiley-Interscience, 2 edition, July 2006. [2] S. Vaj…

数据结构:(5)算法分析基础

算法时间复杂度分析 算法空间复杂度分析

蠢货别忘(一)common lisp funcall

自定义 cons&#xff0c;car&#xff0c;cdr Scheme 示例&#xff1a; (define (my_cons x y) (lambda (z) (z x y))) (define (my_car m) (m (lambda (p q) p))) (define (my_cdr m) (m (lambda (p q) p))) Common Lisp&#xff1a; (defun my_cons (x y) (lambda (z) (funcal…

[Leetcode][第35题][JAVA][搜索插入位置][二分法]

【问题描述】[中等] 【解答思路】 二分法 时间复杂度&#xff1a;O(LogN) 空间复杂度&#xff1a;O(1) public class Solution {public int searchInsert(int[] nums, int target) {int len nums.length;if (len 0) {return 0;}// 特判if (nums[len - 1] < target) {re…

数据结构:(6)其他情况的算法分析

最好&#xff0c;最坏,平均复杂度分析 递归算法的时间复杂度分析

树状数组的区间修改+查询

首先看树状数组是用来求前缀和比较方便的一种数据结构 sum[i] Sigma a[i] Sum(bit[x]&#xff09; 而区间修改也不难实现 就是引入一个差分数组del del[i]表示对i~n的修改 这样的话也就是最del[i]求前缀和 就能得到i~n的所有修改了 因为i前的每一个元素的修改都是对后面…

scrapy爬虫系列之五--CrawlSpider的使用

功能点&#xff1a;CrawlSpider的基本使用 爬取网站&#xff1a;保监会 主要代码&#xff1a; cf.py # -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule import reclass CfSpider(CrawlSp…

洛谷P4718 【模板】Pollard-Rho算法

虽然很久以前就听说过PR算法&#xff0c;但前几天第一次打。 首先miller rabin判断素数&#xff0c;不在复杂度瓶颈。 pollard rho倍增环长&#xff0c;复杂度是\(O(n^{\frac{1}{4}} log n)\)的。 然而这样复杂度较高&#xff0c;比较难过加强后的数据。 可以考虑每次倍增时把乘…

[密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第10篇]RSA和强RSA问题有什么区别

这个密码学52件事数学知识的第一篇,也是整个系列的第10篇.这篇介绍了RSA问题和Strong-RSA问题,指出了这两种问题的不同之处. 密码学严重依赖于这样的假设,某些数学问题难以在有限的时间内解决.让我们看公钥(非对称)密码学,这也是这篇文章中我们使用的一个假设----**单向函数(O…

Palindrome subsequence HDU - 4632 区间dp|记忆化搜索

// 区间dpimport java.util.Scanner;/**** author CN*/ public class main {static int mod 10007;static String l;static int[][] dp new int[1010][1010];public static void main(String[] args){// TODO code application logic hereint t;Scanner sc new Scanner(Syst…

课外阅读(通讯技术的发展史)

课外阅读&#xff08;通讯技术的发展史&#xff09; 人们常把有线固定通信和无线移动通信作为信息基础结构&#xff08;NII/GII&#xff09;的两大组成部分。近年来它们都以明显的快速步伐向前推进&#xff0c;而且进入新世纪后将更加快速发展&#xff0c;为兴旺的信息时代作出…

python学习第19天

pass 转载于:https://www.cnblogs.com/heimajia/p/10636469.html

第十三期:你所了解的javascript?

在介绍JavaScript之前&#xff0c;首先让我们来简单了解一下脚本语言。大家知道&#xff0c;HTML通常用于格式化和链接文本&#xff0c;各种编程语言通常用于向机器发出一系列复杂的指令&#xff0c;而脚本语言是介于HTML和C、Java等编程语言之间的语言。脚本语言是一种简单的语…

[密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第12篇]椭圆曲线上的群理论是什么

这是系列中的第12篇,我们继续数学背景的部分,通过介绍椭圆曲线的群理论… 椭圆曲线群定律是一种在一组椭圆曲线有理点中定义的二元操作来形成一个群的方法.现在,让我们看看到底什么意思,和这个东西怎么用 椭圆曲线和它的有理点 在椭圆曲线中加入群理论 这就是全部了吗 这和密…

python学习第22天

封装 properpty classmathod staticmathod 转载于:https://www.cnblogs.com/heimajia/p/10636515.html

[密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第13篇]概述投影点表达的用途的优点

这是52密码学系列中第13篇,我们继续数学背景部分,通过概述投影点表达的使用和优点. TLDR - 在椭圆曲线点上的翻倍和加法操作需要一个域取逆和几个乘法操作.我们考虑域K(特征值既不是2也不是3).给定K上的一个逆运算是比乘法更花费时间的,因此用投影点坐标去计算这些操作是更有效…

第七期:Python 从入门到精通:一个月就够了!

Python 从入门到精通&#xff1a;一个月就够了&#xff01; 对于许多未曾涉足计算机编程的领域「小白」来说&#xff0c;深入地掌握 Python 看似是一件十分困难的事。其实&#xff0c;只要掌握了科学的学习方法并制定了合理的学习计划&#xff0c;Python 从 入门到精通只需要一…