看数据范围像是个暴力,而且理论复杂度似乎可行,然后被卡了两个点。。。然后来了个乱搞的线段树+扫描线。。

3225: [Sdoi2008]立方体覆盖

Time Limit: 2 Sec Memory Limit: 128 MB

Submit: 102 Solved: 64

[Submit][Status][Discuss]

Description

  A君近日为准备省队选拔,特意进行了数据结构的专项训练。训练过程中就遇到了“矩形面积并”这道经典问题,即:给出N个各边与坐标轴平行(垂直)的矩形,求矩形覆盖的面积之和。A君按纵坐标建立线段树后按横坐标扫描计算,轻易AC了这道题,时间复杂度为O(NlogN)。

  为了强化训练,A君将问题推广到三维空间中,即:给出N个各棱与坐标轴平行(垂直)的立方体,求立方体覆盖的体积之和。为了简化问题,令立方体均退化为正立方体,用四元组(x, y, z, r)表示一个立方体,其中x, y, z为立方体的中心点坐标,r为中心点到立方体各个面的距离(即立方体高的一半)。

  这次可难住了A君,只好请你——未来的金牌——来帮助他了。

Input

  第一行是一个正整数N。

  以下N行每行四个整数x, y, z, r,由空格隔开。

Output

  共一个数,即覆盖的总体积。

Sample Input

3

0 0 0 3

1 –1 0 1

19 3 5 6

Sample Output

1944

HINT

对于 100% 的数据,1≤N≤100

对于 100% 的数据,-1000≤x, y, z≤1000,1≤r≤200

线段树+扫描线怎么搞非常容易,即确定一个轴离散另一个,然后分段扫描求面积求和即可。此题二维,可以同理。
直接写个二维的线段树(线段树套线段树)会舒服很多,可惜树套树不是很会,于是乱搞了个。。

于是我先枚举离散后的高,再次基础上控制满足条件的x,y。

利用扫描线的思想,把每一条竖边取出并按x从左到右快排,然后扫描。如果一条边是始边,把线段树中的y1–y2加1,否则把y1–y2减1。然后对于每一个不同的x,把线段树中覆盖层数大于1的个数*(x[i+1]-x[i])。

这个线段树的细节很多,比如线段树建立是l~mid,mid~r,然后叶子节点是l~l+1。

code:

#include<cstdio>
#include<algorithm>
using namespace std;
int read()
{
int x=0,f=1; char ch=getchar();
while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
#define maxn 1010
const int ff=1200; struct tre{int sum,del,l,r;}tree[210*2*16];
int x1[110],x2[110],y1[110],y2[110],z1[110],z2[110];
int tz,tZ,ty,tY;;
int Z[220],Y[220],z[220],y[220];
int n,t,tmp;
int ans=0;
struct data{int x,l,r,f;}xd[220];
int pp[2500];int to;
int L,R,F;int h,W; void build(int now,int l,int r)
{
tree[now].l=l,tree[now].r=r;
tree[now].sum=tree[now].del=0;
if (l==r || l+1==r) return;
int mid=(l+r)>>1;
build(now<<1,l,mid);
build(now<<1|1,mid,r);
} void insert(int now)
{
if (L<=tree[now].l && R>=tree[now].r)
{
if (!F) tree[now].del++,tree[now].sum=y[tree[now].r]-y[tree[now].l]; else
if (!(--tree[now].del)) tree[now].sum=(tree[now].l+1>=tree[now].r)?0:tree[now<<1].sum+tree[now<<1|1].sum;
return;
}
int mid=(tree[now].l+tree[now].r)>>1;
if (L<mid) insert(now<<1);
if (R>mid) insert(now<<1|1);
if (!tree[now].del) tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum;
} bool cmp(data a,data b)
{
if (a.x!=b.x) return a.x<b.x;
return !a.f&&b.f;
} int main()
{
n=read();
for (int i=1; i<=n; i++)
{
int xx=read(),yy=read(),zz=read(),r=read();
x1[i]=xx-r;x2[i]=xx+r;
y1[i]=yy-r;y2[i]=yy+r;
z1[i]=zz-r;z2[i]=zz+r;
} for (int i=1; i<=n; i++)
Z[++tZ]=z1[i],Z[++tZ]=z2[i];
sort(Z+1,Z+tZ+1);Z[0]=Z[1]-1;
for (int i=1; i<=tZ; i++) if (Z[i]!=Z[i-1]) z[++tz]=Z[i]; for (int i=1; i<tz; i++)
{
h=z[i+1]-z[i];
t=ty=tY=0;
to=tmp=0;
for (int j=1; j<=n; j++)
if (z1[j]<=z[i] && z[i+1]<=z2[j])
{
xd[++t].x=x1[j],xd[t].l=y1[j],xd[t].r=y2[j],xd[t].f=0;
xd[++t].x=x2[j],xd[t].l=y1[j],xd[t].r=y2[j],xd[t].f=1;
Y[++tY]=y1[j],Y[++tY]=y2[j];
}
sort(Y+1,Y+tY+1);Y[0]=Y[1]-1;
for (int j=1; j<=tY; j++) if (Y[j]!=Y[j-1]) y[++ty]=Y[j],pp[Y[j]+ff]=++to;
if (!ty) continue;
sort(xd+1,xd+t+1,cmp); build(1,1,ty); for (int j=1; j<t; j++)
{
W=xd[j+1].x-xd[j].x;
L=pp[xd[j].l+ff],R=pp[xd[j].r+ff],F=xd[j].f;
insert(1);
if (xd[j+1].x!=xd[j].x || j+1==t) tmp+=tree[1].sum*W;
}
ans+=h*tmp;
}
printf("%d\n",ans);
return 0;
}

BZOJ-3225 立方体覆盖 线段树+扫描线+乱搞的更多相关文章

  1. 覆盖的面积 HDU - 1255 (线段树-扫描线)模板提

    给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1& ...

  2. BZOJ 4422 Cow Confinement (线段树、DP、扫描线、差分)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4422 我真服了..这题我能调一天半,最后还是对拍拍出来的...脑子还是有病啊 题解: ...

  3. 线段树扫描线(一、Atlantis HDU - 1542(覆盖面积) 二、覆盖的面积 HDU - 1255(重叠两次的面积))

    扫描线求周长: hdu1828 Picture(线段树+扫描线+矩形周长) 参考链接:https://blog.csdn.net/konghhhhh/java/article/details/7823 ...

  4. hdu1255 覆盖的面积 线段树-扫描线

    矩形面积并 线段树-扫描线裸题 #include<stdio.h> #include<string.h> #include<algorithm> #include& ...

  5. BZOJ 1818 线段树+扫描线

    思路: 可以把题目转化成 给你一些沿坐标轴方向的线段 让你求交点个数 然后就线段树+扫描线 搞一搞 (线段不包含断点 最后+n 这种方式 比线段包含断点+各种特判要好写得多) //By SiriusR ...

  6. 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)

    D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...

  7. 【POJ-2482】Stars in your window 线段树 + 扫描线

    Stars in Your Window Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11706   Accepted:  ...

  8. POJ-1151-Atlantis(线段树+扫描线+离散化)[矩形面积并]

    题意:求矩形面积并 分析:使用线段树+扫描线...因为坐标是浮点数的,因此还需要离散化! 把矩形分成两条边,上边和下边,对横轴建树,然后从下到上扫描上去,用col表示该区间有多少个下边,sum代表该区 ...

  9. hdu 1828 线段树扫描线(周长)

    Picture Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Sub ...

随机推荐

  1. XUtils===XUtils3框架的基本使用方法

    转载自:http://blog.csdn.NET/a1002450926/article/details/50341173 今天给大家带来XUtils3的基本介绍,本文章的案例都是基于XUtils3的 ...

  2. 通过JDBC进行简单的增删改查(二)

    本章笔记更易理解和学习,也是我第一次初学的笔记. package javastudy; import java.sql.Connection; import java.sql.DriverManage ...

  3. Android性能测试工具Emmagee介绍

    Emmagee介绍 Emmagee是监控指定被测应用在使用过程中占用机器的CPU.内存.流量资源的性能测试小工具.该工具的优势在于如同windows系统性能监视器类似,它提供的是数据采集的功能,而行为 ...

  4. AE二次开发技巧之撤销、重做

    原文地址:http://www.cnblogs.com/wylaok/articles/2363208.html 可以把AE自带的重做.撤销按钮或工具添加到axToolBarControl上,再把ax ...

  5. KVM虚拟机网络基础及优化说明

    一个完整的数据包从虚拟机到物理机的路径是: 虚拟机--QEMU虚拟网卡--虚拟化层--内核网桥--物理网卡 KVM的网络优化方案,总的来说,就是让虚拟机访问物理网卡的层数更少,直至对物理网卡的单独占领 ...

  6. IIS mime类型

    参考网站:http://www.iwms.net/n1381c2.aspx 以下例子为iis6.0 下载安卓.苹果安装包时候,需要添加mime类型才可以下载,否则访问不到 安卓 .apk  appli ...

  7. VC/Wince 实现仿Win8 Metro风格界面3——按钮移动交换、删除、添加快捷方式(附效果图)

    上一篇文章写了如何进行页面滑动切换,今天我讲一下如何实现两个按钮拖动交换位置,包括同一个页面按钮交换或者两个页面之间的按钮交换.另外就是如何拖动删除界面上的快捷方式.按钮交换和拖动删除,这两个功能基本 ...

  8. sql截取

    String sql2="select count(*) from t_testuser where substr(INSETTIME,1,10)=to_char(sysdate,'yyyy ...

  9. Linux常用指令---tar | zip (解压缩)

    减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间.gzip是在Linux系统中经常使用的一个对文件进行压缩和解压缩的命令,既方便又好用.gzip不仅可以用 ...

  10. HoloLens开发手记 - Unity之场景共享 Shared holographic experiences in Unity

    佩戴HoloLens的多个用户可以使用场景共享特性来获取集合视野,并可以与固定在空间中某个位置的同一全息对象进行交互操作.这一切是通过空间锚共享(Anchor Sharing)来实现的. 为了使用共享 ...