【Rain in ACStar HDU-3340】
·你正从AC星球返回,天又下起凸包雨,只好到线段树下躲雨。
·英文题,述大意:
一个竖直平面的美丽天空,会下凸包雨。凸包雨指的是边数为3~6的多边形,并且每一个它都遵守一个神奇定律,那就是自己不会有两个横坐标相同的点(即每个凸包自己的顶点不会出现在一条垂直于x轴的直线上)。现在有Q个操作:第一种是放置一个凸包雨(即输入其边数,并从其横坐标最小点开始顺时针读入顶点坐标[x,y<=1000000000]);第二种是询问,即读入l,r来询问我们横坐标在[l,r]之间的雨滴的面积总和(被切开的雨也算),也就是求[l,r]的凸包总面积。(Q<=25000)
·分析:
凸包雨很多,询问很多。我们需要使用数据结构加以维护。请选择一款你是喜爱的数据结构满足以下条件:①你喜欢②可以维护区间的凸包面积!
但问题是这是一个二维的问题,我们需要加以转化,目的是使每个凸包的面积便于使用某种美妙的数据结构维护。
尝试将计算形形色色的凸包的方法单一化,我们从一个简单可爱的四边形入手:现在知道其顶点坐标,怎么求面积?

我们探索面积求法的目的需要再次说明:使得对各种多边形面积计算的方法单一化。从坐标的角度思考,我们可以想到作差法(这很常用),但是选择它的一个主要原因是,可以将任意多边形分解为几个梯形的面积加加减减的美好结果(当然,矩形,三角形这里可看做特殊的梯形,因为它们的面积计算同样满足:S=(l1+l2)*h/2)。即:将面积计算方法单一化。如图:

如美丽的图:我们发现,四边形面积就可以使用两个绿色梯形的面积减去两个黄色梯形的面积。很开心发现这个结论。但是我们需要进一步推广,获得一个普遍的计算方式。我们需要快速确定什么该减什么时候该加。顺着输入的顺序(从最左边点的逆时针)如图:

按照读入顺序,我们根据上文结论,可以知道,这个多边形的面积是上顶点为(5 1)(4 5)的梯形面积和减去上顶点为(1 2)(2 3)(3 4)的梯形面积。接着你就惊奇地发现,有规律:按照逆时针顺序,对于一个点a,如果它的上一个点的横坐标比它小,那么以它俩为上顶点的梯形面积就要减去;反之,如果是横坐标大,则这个梯形的面积就要加上(想一想,很容易)。所以在读入后就可以按照这个方法了。
怎么操作?现在我们获得了求梯形面积的方法,基于相邻每个点的坐标。这个时候就是数据结构了。对于一个梯形,就用小学的面积公式,意思说我们只需要维护上下底的长度(即两个点的纵坐标)。如个图:

你决定了,要使用线段树啦啦。实际上写代码时候,我们可以引入一个思想和一个变量来使得CODING更加美妙。思想是我们可以看做是线段树维护等差数列(注意维护等差数列的基本思路:维护左右端点和公差)。方法是引入公差,即凸包那一条边的斜率,这样便于计算在线段树PushDown的时候的中间数。
线段树的特别的参数有:A(左端点加的值,即等差数列第一项),B(左端点加的值),ratio(斜率),它们对应的Lazy数组是:a[],b[],G[],另外,需要维护一个Sum[]表示当前区间的面积和(面积加加减减)。例子在这里:(例如向区间[1,4]插入等差数列{1,2,3,4})

最后是一些美妙的提醒和细节处理:
①注意在Lazy下放和线段树区间分裂时都可能会有取中项的操作
②离散化询问,以及点的横坐标(所以在计算的时候一定要调用原长)
③本题的一个线段树叶子结点是l+1==r表示一段小区间。
④在PushDown时和update到达指定区间时都需要计算Sum(即Sum[u]+=)
剩下的都在代码里面,无比美妙。
#define D double
#define lch u<<1
#include<stdio.h>
#define rch u<<1|1
#define M (l+r>>1)
#include<algorithm>
#define Up Sum[u]=Sum[lch]+Sum[rch]
#define go(i,a,b) for(int i=a;i<=b;i++)
#define Rar(a) a=lower_bound(T+1,T+n+1,a)-T
using namespace std;
const int N=;char c[N];
int C,m,t,tt,kk,k,n,len[N],T[N],I,J;
D A[N*],B[N*],Sum[N*],G[N*],ratio,ans;
struct Q{int l,r;}q[N];struct P{int x,y;}p[N][];
D Cal(D a,int s,D rate){return 1.0*a+1.0*s*rate;}
void build(int u,int l,int r)
{
A[u]=B[u]=Sum[u]=G[u]=;if(l+==r)return;
build(lch,l,M);build(rch,M,r);
}
void Down(int u,int l,int r)
{
G[lch]+=G[u],G[rch]+=G[u];A[lch]+=A[u];B[rch]+=B[u];
D Z=Cal(A[u],T[M]-T[l],G[u]);
Sum[lch]+=1.0*(A[u]+Z)*(T[M]-T[l])/;
Sum[rch]+=1.0*(Z+B[u])*(T[r]-T[M])/;
B[lch]+=Z,A[rch]+=Z,A[u]=B[u]=G[u]=;
}
void update(int u,int l,int r,int L,int R,D a,D b)
{
if(L<=l&&r<=R){A[u]+=a;B[u]+=b;G[u]+=ratio;
Sum[u]+=1.0*(a+b)*(T[r]-T[l])/;return;}Down(u,l,r);
if(R<=M)update(lch,l,M,L,R,a,b);
else if(L>=M)update(rch,M,r,L,R,a,b);
else{D Z=Cal(a,T[M]-T[L],ratio);
update(lch,l,M,L,M,a,Z);update(rch,M,r,M,R,Z,b);}Up;
}
void query(int u,int l,int r,int L,int R)
{
if(L<=l&&r<=R){ans+=Sum[u];return;};Down(u,l,r);
if(L<M)query(lch,l,M,L,R);
if(R>M)query(rch,M,r,L,R);
}
int main(){scanf("%d",&C);while(C--&&scanf("%d",&m))
{
n=k=t=tt=kk=;
go(i,,m){scanf(" %c",&c[i]);
if(c[i]=='R'&&scanf("%d",&len[++t]))
go(j,,len[t])scanf("%d%d",&p[t][j].x,&p[t][j].y),T[++n]=p[t][j].x;
if(c[i]=='Q'&&scanf("%d%d",&q[k].l,&q[++k].r))T[++n]=q[k].l,T[++n]=q[k].r;} sort(T+,T+n+);n=unique(T+,T+n+)-T-;
go(i,,k)Rar(q[i].l),Rar(q[i].r);build(,,n);
go(i,,t)go(j,,len[i])Rar(p[i][j].x); go(i,,m)if(c[i]=='R'&&++tt)go(j,,len[tt])
{
I=j,J=j!=len[tt]?j+:;
int x1=p[tt][I].x,y1=p[tt][I].y,x2=p[tt][J].x,y2=p[tt][J].y;
if(x1<x2)y1*=-,y2*=-;else swap(x1,x2),swap(y1,y2);
ratio=1.0*(y2-y1)/(T[x2]-T[x1]);update(,,n,x1,x2,y1,y2);
}
else ++kk,ans=,query(,,n,q[kk].l,q[kk].r),printf("%.3f\n",ans);
}return ;}//Paul_Guderian
人们在卑微地倒立,可楼群却都高高在上,
这是不能接受的事实,真实得就像梦境一样。————汪峰《不能接受的事实》
【Rain in ACStar HDU-3340】的更多相关文章
- 【Windows Of CCPC HDU - 6708】【打表,找规律】
题意分析 HDU - 6708 题意:给出一个整数k,要求你输出一个长和宽均为2^k^ 的符合要求的矩阵.比如k等于1时输出 \[ \begin{matrix} C & C \\ P & ...
- 【还是畅通工程 HDU - 1233】【Kruskal模板题】
Kruskal算法讲解 该部分内容全部摘录自刘汝佳的<算法竞赛入门经典> Kruskal算法的第一步是给所有边按照从小到大的顺序排列. 这一步可以直接使用库函数 qsort或者sort. ...
- 【Difference Between Primes HDU - 4715】【素数筛法打表+模拟】
这道题很坑,注意在G++下提交,否则会WA,还有就是a或b中较大的那个数的范围.. #include<iostream> #include<cstdio> #include&l ...
- HDU 3340 Rain in ACStar(线段树+几何)
HDU 3340 Rain in ACStar pid=3340" target="_blank" style="">题目链接 题意:给定几个多 ...
- hdu 3340 Rain in ACStar 线段树区间等差数列更新
Rain in ACStar Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/problem/show/1385 ...
- HDU 5950 Recursive sequence 【递推+矩阵快速幂】 (2016ACM/ICPC亚洲区沈阳站)
Recursive sequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Other ...
- 【数位dp】【HDU 3555】【HDU 2089】数位DP入门题
[HDU 3555]原题直通车: 代码: // 31MS 900K 909 B G++ #include<iostream> #include<cstdio> #includ ...
- 【HDU 5647】DZY Loves Connecting(树DP)
pid=5647">[HDU 5647]DZY Loves Connecting(树DP) DZY Loves Connecting Time Limit: 4000/2000 MS ...
- -【线性基】【BZOJ 2460】【BZOJ 2115】【HDU 3949】
[把三道我做过的线性基题目放在一起总结一下,代码都挺简单,主要就是贪心思想和异或的高斯消元] [然后把网上的讲解归纳一下] 1.线性基: 若干数的线性基是一组数a1,a2,a3...an,其中ax的最 ...
随机推荐
- Raid 5数据恢复原理以及raid 5数据恢复实际操作案例
Raid 5数据恢复算法原理 要理解 raid 5数据恢复原理首先要先认识raid5,"分布式奇偶校验的独立磁盘结构"也就是我们称之为的raid 5数据恢复有一个概念需要理解,也就 ...
- vue jsx 使用指南
vue jsx 使用指南 vue jsx 语法与 react jsx 还是有些不一样,在这里记录下. let component = null // if 语句 if (true) { compone ...
- Nagios监控的部署与配置
[安装Nagios] yum install -y httpd httpd-devel httpd-tools mysql mysql-devel mysql-server php php-devel ...
- Python内置函数(55)——globals
英文文档: globals() Return a dictionary representing the current global symbol table. This is always the ...
- Python-socket网络编程-Day8
目录Day8-Python socket 11.Socket 11.1.socket和file的区别: 11.2.WEB服务应用: 21.3.更多功能 21.4.socket方法: 41.5. 服务端 ...
- 从Mybatis源码理解jdk动态代理默认调用invoke方法
一.背景最近在工作之余,把开mybatis的源码看了下,决定自己手写个简单版的.实现核心的功能即可.写完之后,执行了一下,正巧在mybatis对Mapper接口的动态代理这个核心代码这边发现一个问题. ...
- java中的引用类型的对象存放在哪里
根据上下文来确定.比如void func(){ Object obj = new Object();//这个obj在函数的栈里.}class Test{ private Object obj ...
- servlet2.3/2.5/3.0/3.1的xml名称空间备忘
The web.xml is a configuration file to describe how a web application should be deployed. Here’re 5 ...
- 消息队列的使用 RabbitMQ (二): Windows 环境下集群的实现
一.RabbitMQ 集群的基本概念 一个 RabbitMQ 中间件(broker) 由一个或多个 erlang 节点组成,节点之间共享 用户名.虚拟目录.队列消息.运行参数 等, 这个 节点的集合被 ...
- Python基础--函数的定义和调用
一.函数的作用: 提高代码的可读性,减少代码的冗余,方便调用和修改,组织结构清晰 二.函数的定义:函数遵循先定义后调用的原则 1.无参函数 def funcname(): #def 是关键字,后跟函数 ...