【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的最 ...
随机推荐
- easyUI combobox 添加空白项
今天测试反馈了一个问题,希望可以在下拉框下面加一个空白的选项(下拉框用的是combobox方法). 开始分析这个问题: 首先,这个数据都是后台读出来的,那么我在后台直接添加可以么,答案是可以的,如果没 ...
- EasyUI DataGrid 实现单行/多行编辑功能
要实现 EasyUI DataGrid 的可编辑很简单,在需要编辑的列添加 editor [编辑器]就可以了. 单行编辑 // 初始化数据列表 function initDatagrid() { $( ...
- Python爬虫之urllib模块1
Python爬虫之urllib模块1 本文来自网友投稿.作者PG,一个待毕业待就业二流大学生.玄魂工作室未对该文章内容做任何改变. 因为本人一直对推理悬疑比较感兴趣,所以这次爬取的网站也是平时看一些悬 ...
- TortoiseGit安装与使用
公司的源码是在码云上,平时进行项目源码管理和团队开发都会使用到GIT,花了一天时间才将Git搞明白,这是一个工具,我在这里就简单说一下,其安装使用方法,也是对自己学习的总结;本文章适合于刚接触GIT的 ...
- Python内置函数(50)——issubclass
英文文档: issubclass(class, classinfo) Return true if class is a subclass (direct, indirect or virtual) ...
- angular2 学习笔记 ( server-side rendering, angular universal, 服务端渲染 )
更新 : 2018-01-10 大半年过去了依然没有做 server side render 的冲动,但是一直有关注这方便的做法. 今天领悟了一些道理, 这里做个记入. server side re ...
- python的单元测试
单元测试实际上就是一些"断言"(assert)代码 断言就是判断一个函数或对象的一个方法所产生的结果是否符合你期望的那个结果. python中assert断言是声明布尔值为真的判定 ...
- JavaScript中的单体模式四种实现方式
/* 1 简单单体 */ var Singleton = { attr1: 1 , method1:function(){ //do sth } }; alert(Singleton.attr1); ...
- jodatime 时间比较
public ArrayList<CalcPeriod> getCalcPeriods() { DateTime now = DateTime.now(); DateTime.Proper ...
- Extensions in UWP Community Toolkit - ViewExtensions
概述 UWP Community Toolkit Extensions 中有一个为 View 提供的扩展 - View Extensions,本篇我们结合代码详细讲解 View Extensions ...