[线段树 + 离散化]


Description

艾莎女王又开始用冰雪魔法盖宫殿了。

她决定先造一堵墙,于是释放魔法让形为直角梯形的冰砖从天而降,定入冻土之中。

现在你将回答女王的询问:某段冻土上冰砖的面积。

注:多块冰砖之间会互相重叠,重叠部分要多次计算。

Input

第一行一个整数nn,表示有nn个冰砖先后定入了冻土之中。

冻土上刚开始并没有冰砖。

接下来n行,每行6个整数,x1i,h1i,x2i,h2i,li,ri

表示一次如图所示的冰砖下落,并询问在这之后,落在[li,ri][li,ri]内冰砖的总面积。

\(2≤n≤100000, −10^8≤li,ri≤10^8,\)

\(−10^8≤x1i<x2i≤10^8,0≤h1i,h2i≤10000,x2i−x1i≤10^5,\)

\(2 ≤ n ≤ 100000,−10^8≤li<ri≤10^8,−10^8≤x1i<x2i≤10^8,\)

$0≤h1i,h2i≤10000,x2i−x1i≤10^5 $

Output

输出nn行,每行输出一个浮点数,作为对该询问的回答。误差小于1e-6的回答都被当作正确回答。

Sample Input

2

1 1 3 2 -5 5

2 2 4 1 2 3

Sample Output

3.0000000

3.50000000

Hint

如图是对样例输入的解释。

重叠部分需多次计算。


这是一道比较有意义的线段树题目,线段树的每个节点主要保存的是一段区间内的面积和。

然后要想到的是,因为是区间更新区间查询,所以需要用到懒惰标记,避免超时。

想好要用到什么方法,接下来就思考具体方案。

首先,因为是梯形,所以更新是要用到左边高度和右边高度,即梯形的上底和下底,懒惰标记也需要传递这两个值。在往下传递的时候,可以把中间的一条线分两次计算,即把梯形分成矩形和三角形两个部分,第一个部分很好得,直接是矩形的上底,第二个部分可以用相似三角形来求。

需要注意的是,由于l ~ r 中存储的是l ~ r+1的值,所以左子树中存储l ~ mid+1,,右子树中存储mid+1 ~ r+1

还需要注意的一点是,题目中由于x 范围很大,需要离散化。

下面是代码

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define ls u<<1,l,mid
#define rs u<<1|1,mid+1,r const int maxn = 1e5 + 5;
int n;
int cnt = 1;//离散化之后点的总数
int num[maxn << 2]; struct node {// 在线段树中, l ~ r维护的是l ~ r+1 的值
double sum;
double addl,addr;
}nod[maxn << 2 << 2]; struct que { //存储询问,因为需要先读入所有点用于离散化
int xl,xr,hl,hr,x,y;
}q[maxn]; void pushup(int u){
nod[u].sum = nod[u<<1].sum + nod[u<<1|1].sum;
} void build(int u,int l,int r){
if(l == r) return;
int mid = (l + r) >> 1;
build(ls);
build(rs);
pushup(u);
} void init(){// 读入询问,离散化,建树
scanf("%d",&n);
for(int i = 1;i <= n;i++){
scanf("%d%d%d%d%d%d",&q[i].xl,&q[i].hl
,&q[i].xr,&q[i].hr
,&q[i].x ,&q[i].y );
num[cnt] = q[i].xl;cnt++;
num[cnt] = q[i].xr;cnt++;
num[cnt] = q[i].x;cnt++;
num[cnt] = q[i].y;cnt++;
}
sort(num + 1, num + cnt);
cnt = unique(num+1,num+cnt) - num - 1;
build(1,1,cnt-1);
} void pushdown(int u,int l,int r){
if(l == r){nod[u].addl = nod[u].addr == 0;return;}
//计算中间点的高度
int mid = (l + r) >> 1;
int rr = num[r+1] - num[l];
int midd = num[mid+1] - num[l];
double add = nod[u].addl + (nod[u].addr - nod[u].addl) * midd / rr;
//向下传递sum值
nod[u<<1].sum += (nod[u].addl + add) * midd / 2;
// nod[u<<1|1].sum += (nod[u].addr + add) * (rr - midd) / 2;
nod[u<<1|1].sum = nod[u].sum - nod[u<<1].sum;
//向下传递add,并将当前节点add值清零
nod[u<<1].addl += nod[u].addl; nod[u].addl = 0;
nod[u<<1].addr += add;
nod[u<<1|1].addr += nod[u].addr; nod[u].addr = 0;
nod[u<<1|1].addl += add;
} void update(int u,int l,int r,int x,int y,double hl,double hr){
if(l == x && r+1 == y){
nod[u].addl += hl;
nod[u].addr += hr;
nod[u].sum += (hl + hr) * (num[y]-num[x]) / 2;
return;
}
int mid = (l + r) >> 1;
if(nod[u].addl || nod[u].addr)pushdown(u,l,r);
if(y <= mid+1) update(ls,x,y,hl,hr);
else if(x >= mid+1) update(rs,x,y,hl,hr);
else {
int rr = num[y] - num[x];
int midd = num[mid+1] - num[x];
double add = hl + (hr - hl) * midd / rr;
update(ls,x,mid+1,hl,add);
update(rs,mid+1,y,add,hr);
}
pushup(u);
} double query(int u,int l,int r,int x,int y){
if(l == x && r + 1 == y)return nod[u].sum;
int mid = (l + r) >> 1;
if(nod[u].addl || nod[u].addr)pushdown(u,l,r);
if(y <= mid+1) return query(ls,x,y);
if(x >= mid+1) return query(rs,x,y);
return query(ls,x,mid+1) + query(rs,mid+1,y);
} void work(){
for(int i = 1;i <= n;i++){
int x = lower_bound(num + 1,num + cnt + 1,q[i].xl) - num ;
int y = lower_bound(num + 1,num + cnt + 1,q[i].xr) - num ;
update(1,1,cnt-1,x,y,q[i].hl,q[i].hr);
x = lower_bound(num + 1,num + cnt + 1,q[i].x) - num ;
y = lower_bound(num + 1,num + cnt + 1,q[i].y) - num ;
printf("%lf\n",query(1,1,cnt-1,x,y));
}
} int main(){
init();
work();
return 0;
}

最新文章

  1. 来玩Play框架05 数据库
  2. StringUtils.isNumeric使用
  3. XMemcached使用示例--转
  4. 读书笔记--用Python写网络爬虫01--网络爬虫简介
  5. c#中的jQuery——HtmlAgilityPack
  6. ios可变数组的所有操作
  7. MVC框架中,遇到 [程序集清单定义与程序集引用不匹配]怎么办?
  8. 跟着刚哥学习Spring框架--创建HelloWorld项目(一)
  9. 动态渲染页面爬取-Selenium &amp; Splash
  10. 基于HTML5 的互联网+地铁行业
  11. SharePoint Framework 基于团队的开发(三)
  12. renameTo()判断文件是否被占用(判断大文件是否完成拷贝这个动作)
  13. SparkML之推荐引擎(二)---推荐模型评估
  14. Spark记录-Spark性能优化解决方案
  15. 单片机中printf函数的重映射
  16. selenium 自动化安装火狐谷歌插件
  17. 虚拟机VM下CentOS7部署WASND9+HTTP9
  18. GDI基础(1):绘制线条和图形
  19. [日常] Linux下的docker实践
  20. leetcode 121 买卖股票的最佳时机

热门文章

  1. 变形--原点 transform-origin
  2. hdu5322 Hope
  3. Linux内核之旅 链表实现
  4. 异常:Struts:org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find BasicDataSource
  5. C# eval()函数浅谈
  6. jquery stop
  7. Html基础知识讲解
  8. 鸟哥的linux私房菜学习记录之开机流程、模块管理与Loader
  9. Linux内核配置机制(make menuconfig 、Kconfig、Makefile)讲解【转】
  10. iOS 解决的问题