扫描线总结【线段树特殊性质,没有pushdown、query操作】
扫描线
题意
多个矩阵求交集,线段树的特殊操作,非常特殊的情况,一堆证明之后,就没有pushdown操作。
没有pushdown操作,也没有query操作,直接tr[1].len.
亚特兰蒂斯
由于点可能有小数,先l、离散化为整数,这里的线段树存的是一个区间:【L,R),左闭右开的区间。 换句话:线段树存的是第几个小区间,那么操作(l,r)的话,对线段树操作:l–r-1就够了,(存的不是点,是小区间,小区间比点的数量少1)
另外,也不需要query()函数,之间调用tr[1].len,返回线段长度
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mst(s,_s) memset(s, _s, sizeof(s))
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;
const int N = 1e6+100;
int T,n,m;
struct seg1{
double x,y1,y2;
int k;
bool operator<(const seg1 & t)const{
return x<t.x;
}
}seg[N];
struct node{
int l,r,cnt;
double len;
}tr[N];
vector<double>ys;
double find(double y)
{
return lower_bound(ys.begin(),ys.end(),y) - ys.begin();
}
void build(int u,int l,int r)
{
if(l==r) tr[u]={l,r,0,0.0};
else{
tr[u]={l,r,0,0.0};
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
}
}
void pushup(int u)
{
if(tr[u].cnt)
{
tr[u].len=(ys[tr[u].r+1]-ys[tr[u].l]);
}
else if(tr[u].l!=tr[u].r)
{
tr[u].len= tr[u<<1].len+tr[u<<1|1].len;
}
else tr[u].len=0;
}
void modify(int u,int l,int r,int k)
{
if(tr[u].l>=l && tr[u].r<=r)
{
tr[u].cnt+=k;
pushup(u);
}
else{
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) modify(u<<1,l,r,k);
if(r>mid) modify(u<<1|1,l,r,k);
pushup(u);
}
}
int main() {
int T=1;
while(cin>>n)
{
if(n==0) break;
ys.clear();
for(int i=0,j=0;i<n;i++)
{
double x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
ys.push_back(y1);
ys.push_back(y2);
seg[j++]={x1,y1,y2,1};
seg[j++]={x2,y1,y2,-1};
}
sort(seg,seg+n*2);
sort(ys.begin(),ys.end());
ys.erase(unique(ys.begin(),ys.end()),ys.end());
build(1,0,ys.size()-2);
double res=0.0;
for(int i=0;i<2*n;i++)
{
if(i>0) res+=(tr[1].len * (seg[i].x-seg[i-1].x));
modify(1,find(seg[i].y1),find(seg[i].y2) -1 ,seg[i].k);
}
printf("Test case #%d\n", T ++ );
printf("Total explored area: %.2lf\n\n", res);
}
return 0;
}
普通版本扫描线
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mst(s,_s) memset(s, _s, sizeof(s))
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;
const int N = 1e6+100;
int T,n,m;
struct seg1{
int x,y1,y2;
int k;
bool operator<(const seg1 & t)const{
return x<t.x;
}
}seg[N];
struct node{
int l,r,cnt;
int len;
}tr[N];
void build(int u,int l,int r)
{
if(l==r) tr[u]={l,r,0,0};
else{
tr[u]={l,r,0,0};
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
}
}
void pushup(int u)
{
if(tr[u].cnt) tr[u].len = tr[u].r+1-tr[u].l;
else if(tr[u].l!=tr[u].r) tr[u].len = tr[u<<1].len+tr[u<<1|1].len;
else{
tr[u].len=0;
}
}
void motify(int u,int l,int r,int k)
{
if(l<=tr[u].l && tr[u].r<=r)
{
tr[u].cnt+=k;
pushup(u);
}
else{
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) motify(u<<1,l,r,k);
if(r>mid) motify(u<<1|1,l,r,k);
pushup(u);
}
}
int main() {
cin>>n;
int m = 0;
for(int i=0,j=0;i<n;i++)
{
int x1,x2,y1,y2;
cin>>x1>>y1>>x2>>y2;
seg[j++]={x1,y1,y2,1};
seg[j++]={x2,y1,y2,-1};
}
//sort(seg, seg + m);
sort(seg,seg+2*n);
build(1,0,10000);
ll res=0;
for(int i=0;i<2*n;i++)
{
if(i>0) res+=tr[1].len * (seg[i].x - seg[i-1].x);
motify(1,seg[i].y1,seg[i].y2-1,seg[i].k);
}
cout<<res<<endl;
return 0;
}
扫描线总结【线段树特殊性质,没有pushdown、query操作】的更多相关文章
- HDU - 1542 扫描线入门+线段树离散化
扫描线算法+线段树维护简介: 像这种求面积的并集的题目,就适合用扫描线算法解决,具体来说就是这样 类似这种给出点的矩形的对角的点的坐标,然后求出所有矩形面积的交集的问题,可以采用扫描线算法解决.图如下 ...
- Atlantis HDU - 1542 (扫描线,线段树)
扫描线的模板题,先把信息接收,然后排序,记录下上边和下边,然后用一条虚拟的线从下往上扫.如果我扫到的是下边,那么久用线段树在这个区间内加上1,表示这个区间现在是有的,等我扫描到上边的时候在加上-1,把 ...
- poj 2482 Stars in Your Window + 51Nod1208(扫描线+离散化+线段树)
Stars in Your Window Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 13196 Accepted: ...
- 【BZOJ 3958】 3958: [WF2011]Mummy Madness (二分+扫描线、线段树)
3958: [WF2011]Mummy Madness Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 96 Solved: 41 Descripti ...
- 洛谷 P4125 [WC2012]记忆中的水杉树【扫描线+set+线段树】
我没有找到能在bzojAC的代码--当然我也WA了--但是我在洛谷过了,那就假装过了吧 minmax线段树一开始写的只能用min更新min,max更新max,实际上是可以互相更新的-- 首先看第二问, ...
- codeforces 447E or 446C 线段树 + fib性质或二次剩余性质
CF446C题意: 给你一个数列\(a_i\),有两种操作:区间求和:\(\sum_{i=l}^{r}(a[i]+=fib[i-l+1])\).\(fib\)是斐波那契数列. 思路 (一) codef ...
- [Usaco2014 Open Gold ]Cow Optics (树状数组+扫描线/函数式线段树)
这道题一上手就知道怎么做了= = 直接求出原光路和从目标点出发的光路,求这些光路的交点就行了 然后用树状数组+扫描线或函数式线段树就能过了= = 大量的离散+模拟+二分什么的特别恶心,考试的时候是想到 ...
- bzoj4822: [Cqoi2017]老C的任务(扫描线+BIT/线段树)
裸题... 依旧是写了BIT和线段树两种(才不是写完线段树后才想起来可以写BIT呢 怎么卡常数都挺大...QAQ ccz和yy的写法好快哇%%% BIT: #include<iostream&g ...
- BZOJ 2588: Spoj 10628. Count on a tree-可持久化线段树+LCA(点权)(树上的操作) 无语(为什么我的LCA的板子不对)
2588: Spoj 10628. Count on a tree Time Limit: 12 Sec Memory Limit: 128 MBSubmit: 9280 Solved: 2421 ...
- 二分+树状数组/线段树(区间更新) HDOJ 4339 Query
题目传送门 题意:给两串字符串,操作1:替换其中一个字符串的某个位置的字符 操作2:查询从p开始相等的最长连续长度 分析:树状数组可以维护一个区间内公共长度(连续)的情况,查询时用二分查找最远的端点即 ...
随机推荐
- python 查找文件夹下以特定字符开头的某类型文件 - os.walk
Python os.walk() 方法 os.walk() 方法用于通过在目录树中游走输出在目录中的文件名,向上或者向下.os.walk() 方法是一个简单易用的文件.目录遍历器,可以帮助我们高效的处 ...
- 简述47种Shader Map的渲染原理与制作方法
https://mp.weixin.qq.com/s/6EVpmgC53HqklIVkIpEssg
- json转化 ts定义网页工具
json转化 ts定义 https://transform.tools/json-to-typescript
- SAP 内外交货单过账
* 交货单过账 DATA: LS_HEADER_DATA TYPE BAPIIBDLVHDRCON, LS_HEADER_CONTROL TYPE ...
- kubeadm安装单master单node节点k8s集群
操作系统:centos7.6 podSubnet(pod 网段) 10.244.0.0/16 serviceSubnet(service 网段): 10.10.0.0/16 集群角色 IP 主机名 安 ...
- php递归算法多级分类
/** * 递归实现无限极分类 * @param $array 分类数据 * @param $pid 父ID * @param $level 分类级别 * @return $list 分好类的数组 直 ...
- unity创建一个数组,让他随机生成一个东西之C#语言(有图教程)
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; ...
- js 判断表格的值
<!DOCTYPE html> <html> <head> <title></title> <meta charset="u ...
- NAT的转换
NAT的转换 拓扑图 Sever0的IP地址:192.168.0.1/24 网关:192.168.0.254 PC0的IP地址:192.168.0.100/24 PC1的IP地址:192.168.0. ...
- golang 解决 socket: too many open files, 以及 too many open files
同事写的一段代,码业务场景:需要多次GET请求一个三方服务的http 接口,获取数据后写入文件.发现有部分文件没有写入.查看日志出现了报错"socket: too many open fil ...