Problem

  给定一个山脉,把山脉的下部看作xOy平面直角坐标系中y=0的直线,用N个来顶点表示山脉。如图:

  Lwins_Y uki有Q个操作,操作有两种:对某个点用魔法(即删点)或询问某个点对空视野的张角(可以超过180°)。譬如上图第3个点的张角是:

Input

第一行包含两个正整数N;Q,分别表示刚开始的时候山的顶点个数以及Lwins_Y uki 的行动个数。
接下来N 行,包含N 对数xi; yi,表示山的顶点的坐标(xi; yi)。
接下来Q 行,每行的格式有如下两种可能:
• 0 k,表示当下时刻Lwins_Y uki 的魔法释放在了一开始的从左往右数的第k 个顶点上。
• 1 k,表示Lwins_Y uki 想立即知道住在第k 个顶点上的生物的对空视野的张角。
输入数据保证Lwins_Y uki 的行动和询问合法,即不会询问或把魔法释放在一个已经消失的点上。

Output

你应该按照询问的顺序,每行回答一次LwinsY uki 的询问,张角用弧度制,保留6 位小数。

Hint

• 对于20% 的数据,N;Q <=1000。
• 对于另外55% 的数据,N;Q<= 30000。
• 对于100% 的数据,N;Q <= 100000。
注意,Lwins_Y uki 不会询问在两侧的顶点的对空视野的张角,但是它有可能使用魔法抹去它们。

Solution

20points:三角函数+(暴力 or 凸壳)

  刚看这题我就懵逼了,然后马上意识到——这题我不可能得分,于是就没管这题。。。
  先思考一下怎么求张角。
  你可以推一推看一看夹角公式,然后学习一下c++的acos()、atan()、atan2()这些函数来解决这个问题。
  当然,我们有一种更简单的做法。
  先让我介绍一下c++的atan2()这个函数。假设某个角θθ\theta的三角函数tanθ=yxtanθ=yxtan\theta=\frac yx,那么atan2(x,y)就会帮你求出θθ\theta这个角的弧度。而根据tan的定义,我们可以把atan2(x,y)理解为原点至点(x,y)的方位角,即与 x 轴的夹角。
  那么,如何用atan2()来求夹角呢?我们可以举个栗子:

  如上图,在平面直角坐标系xOy中,已知a、b的坐标,我们想求∠aOb。那么,我们可以用atan2()先求出∠bOx,再求出∠aOx,两者相减即可。
  解决了张角的求法问题,又有一个问题接踵而至——对于每个询问点O,如何确定其a、b两点?
  以b为例,我们可以画画图发现,我们要求的点b其实就是在O左边的所有点中,满足构成的直线Ob的斜率最小的一个点;点a恰恰相反。这样,我们就可以O(nq)O(nq)O(nq)暴力求出每个询问点的a、b两点。
  当然,我们也可以求个上凸壳。

  但是,囿于他会无耻地删点,所以:
  时间复杂度:O(nq)O(nq)O(nq)。

Code

  我并没有打啦╮(╯▽╰)╭

100points:CDQ分治

  我们发现他会删点,用数据结构不好维护,所以考虑CDQ分治。
  如果单纯地将操作进行分治,那么时间复杂度不好把握。因为我们的操作是删点,如果没有删点,就一直会有n个点,然后所有询问都要花费巨额时间,这样甚至会退化到比暴力还慢的O(nqlog2q)O(nqlog2q)O(nqlog_2q)。
  那么,我们可以将删点转化为加点。如果有些点没有被删过,就把它在最后删掉;然后将操作数组反转过来。
  打到一半,我又发现一个问题:询问点不能插入到那个凸壳里,所以我们对于每个询问点,都要暴力扫一遍栈,找到询问点在凸壳中的上一个点。
  不过,囿于数据是随机的某种原因,这样也过了,而且还很快:

  其实这个可以二分。
  以求点p的张角的左边为例,我们先将所有x坐标小于p的点做个上凸壳,然后加入一个栈中。我们可以发现:栈中有一半的点满足向量p-sta[i-1]在直线sta[i]-sta[i-1]左边,这样我们看的时候,sta[i-1]这个点会被sta[i]遮住;而有另一半的点满足向量p-sta[i-1]在直线sta[i]-sta[i-1]右边。具象地说,有一半的点不能被看见,有一半的点能被看见。这显然满足二分性质,所以我们二分那个中间点。
  然后,求左右手向就可以用叉积。
  时间复杂度:O((n+q)∗(log2(n+q))2)O((n+q)∗(log2(n+q))2)O((n+q)*(log_2(n+q))^2)。
  尽管时间复杂度分析起来是比上面的方法快的,然而这种方法的代码竟然比上面的方法还慢:

Code

  囿于此题代码过于高级,所以我会作下一些批注。

#include <cstdio>
#include <cmath>
#include <algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef double db;const int N=1e5+1,Q=N<<1;
const db pi=acos(-1);//c++的三角函数是弧度制,而cos(π)=-1
int i,n,q,type[Q],query[Q];
bool del[N];
db left[Q];//Solution中所述的∠bOx
db right[Q];//Solution中所述的∠aOx
struct DOT//定义一个点或一个向量
{db x,y;DOT(db _x=0,db _y=0){x=_x,y=_y;}
}a[N];
DOT operator-(DOT a,DOT b){return DOT(a.x-b.x,a.y-b.y);}
inline bool cmpx(const DOT &x, const DOT &y) {return x.x < y.x;}
void scan()
{scanf("%d%d", &n, &q);fo(i,1,n)scanf("%lf%lf", &a[i].x, &a[i].y);sort(a + 1, a + 1 + n, cmpx);fo(i,1,q){scanf("%d%d", &type[i], &query[i]);del[query[i]]|=!type[i];}fo(i,1,n) if (!del[i]) query[++q] = i;//将没有被删的点在最后删掉fo(i,1,q/2){swap(type[i], type[q - i + 1]);swap(query[i], query[q - i + 1]);}//将删点转为加点fo(i,1,q)left[i] = 1.5 * pi, right[i] = -0.5 * pi;//弧度制的1.5*pi即为270°,-0.5*pi即为-90°
}int num[N],top;
DOT poi[N],sta[N];
inline bool cmp(int x, int y) {return a[query[x]].x < a[query[y]].x;}
inline db cro(DOT a,DOT b){return a.x*b.y-a.y*b.x;}//叉积
inline db cross(DOT o,DOT a,DOT b){return cro(a-o,b-o);}
void work(int pn,int qn)
{if(!pn||!qn)return;sort(poi+1,poi+pn+1,cmpx);sort(num+1,num+qn+1,cmp);top=0;int i,j=1;fo(i,1,qn)//顺序做一遍{DOT p=a[query[num[i]]];for (; j <= pn && poi[j].x < p.x; j++){while(top>1) if (cross(sta[top-1], sta[top], poi[j]) > 0)top--;else break;//维护上凸壳sta[++top] = poi[j];}if(!top)continue;int l=1,r=top,mid;while(l<r){mid=l+r+1>>1;if(cross(sta[mid-1],sta[mid],p)>0)r=mid-1;else    l=mid;}db t = atan2(sta[l].y - p.y, sta[l].x - p.x);//计算Solution中所述的∠bOxif (t < 0) t += 2 * pi;//atan2()的返回值是-pi~pileft[num[i]] = min(left[num[i]], t);//bOx要尽量小}top=0;j=pn;fd(i,qn,1)//逆序做一遍{DOT p=a[query[num[i]]];for (; j >= 1 && poi[j].x > p.x; j--){while(top>1) if (cross(sta[top-1], sta[top], poi[j]) < 0)top--;else break;sta[++top] = poi[j];}if(!top)continue;int l=1,r=top,mid;while(l<r){mid=l+r+1>>1;if(cross(sta[mid-1],sta[mid],p)<0)r=mid-1;else    l=mid;}db t = atan2(sta[l].y - p.y, sta[l].x - p.x);//计算Solution中所述的∠aOxright[num[i]] = max(right[num[i]], t);//∠aOx要尽量大}
}
void CDQpartition(int l,int r)
{if(l==r)return;int mid=l+r>>1;int pn=0;fo(i,l,mid)if(!type[i])poi[++pn]=a[query[i]];//记录左边的加点int qn=0;fo(i,i,r  )if( type[i])num[++qn]=i;//记录右边的询问work(pn,qn);if(pn&&pn<mid-l+1)CDQpartition(l    ,mid);if(qn&&qn<r-mid  )CDQpartition(mid+1,r  );
}void print()
{fd(i,q,1)if(type[i]){db t=left[i]-right[i];if (t < 0) t += 2 * pi;if (t > 2 * pi) t -= 2 * pi;printf("%.6f\n",t);}
}int main()
{scan();CDQpartition(1,q);print();
}

【JZOJ4117】lhxsb(三角函数+凸壳+CDQ分治)相关推荐

  1. 时空旅行[线段树分治][维护凸壳]

    文章目录 前言 题目 思路 代码 前言 肝了一上午-这是我才学线段树分治的例题-真舒服 题目 温馨提示:首先在UOJ做,LOJ挖数据,BZOJ终极评测... UOJ198 二手剽- 思路 为什么不能用 ...

  2. bzoj2961 共点圆 (CDQ分治, 凸包)

    /* 可以发现可行的圆心相对于我们要查询的点是在一个半平面上, 然后我们要做的就是动态维护凸壳然后用这个半平面去切它 看看是否是在合法的那一面然后cdq分治就可以了代码基本是抄的,*/#include ...

  3. 洛谷P3122 [USACO15FEB]圈住牛Fencing the Herd(计算几何+CDQ分治)

    题面 传送门 题解 题目转化一下就是所有点都在直线\(Ax+By-C=0\)的同一侧,也就可以看做所有点代入\(Ax+By-C\)之后的值符号相同,我们只要维护每一个点代入直线之后的最大值和最小值,看 ...

  4. NOI2007 货币兑换 - CDQ分治斜率优化dp

    斜率优化dp维护一个凸壳.如果\(x, y\)坐标都递增,可以用单调队列,如果只有\(x\)递增,可以在凸壳上二分斜率,如果\(x, y\)都不递增,则需要在凸包中插入,可以用平衡树或cdq分治维护. ...

  5. 【NOI2007】货币兑换【任意坐标斜率优化】【CDQ分治】

    题意:有 A,B 两种金券,给出 nnn 天内分别的单位价格和可以购买的数量的比例.开始有 SSS 元,求 nnn 天后最多能有多少元. 提示:每次操作一定全买全卖 n≤105n\leq 10^5n≤ ...

  6. CF932F-Escape Through Leaf【树上启发式合并,CDQ分治,斜率优化dp】

    正题 题面链接:https://www.luogu.com.cn/problem/CF932F 题目大意 nnn个点的一棵树,从xxx跳到yyy(要求yyy在xxx的子树中)会产生Ax∗ByA_x*B ...

  7. P4027-[NOI2007]货币兑换【斜率优化dp,CDQ分治】

    正题 题目链接:https://www.luogu.com.cn/problem/P4027 题目大意 nnn天开始时有SSS元钱,每天AAA种股票价格为aia_iai​,BBB种价格为bib_ibi ...

  8. 点分治+CDQ分治+整体二分全纪录

    点分治 点分治讲解 解决树上路径问题 经典例题:点分治(长度小于m的路径计数) 经典例题:点分治(聪聪可可) 经典例题:点分治(多个定值路径计数) 经典例题:点分治(采药) 经典例题:点分治+ST表+ ...

  9. 【BZOJ1492】【NOI2007】—Cash(cdq分治维护凸包优化斜率dp)

    传送门 考虑令f[i]f[i]f[i]为第iii天得到的最多的AAA券,g[i]g[i]g[i]为第iii天得到的最多的BBB券 则g[i]=f[i]/rate[i]g[i]=f[i]/rate[i] ...

最新文章

  1. 16x16点阵汉字c语言,16x16led点阵滚动汉字显示设计。
  2. C#获得枚举类型的长度
  3. python until语句_Python3 循环
  4. 关于寄存器的定义__REG
  5. android 6.0 数据库权限,Android超清晰6.0权限申请AndPermission
  6. docker常用参数详解,docker run常用参数详解(精)
  7. jQuery: 插件开发模式详解 $.extend(), $.fn, $.widget()
  8. xmind 笔记
  9. Leetcode每日一题:面试题02.02.kth-node-from-end-of-list-lcci(返回倒数第k个节点)
  10. react-native gradle
  11. 亿阳信通中标9321.91万元智慧城市建设项目
  12. python定时重新初始化类_如何重新初始化类对象
  13. 网页内嵌多媒体内容的完美实现
  14. 英语“就近原则”和“就远原则”
  15. 服务器打不开网页dns错误是怎么回事,dns配置错误网页打不开
  16. 栈内存和堆内存的区别
  17. 大数据可视化设计开发方案调研
  18. Python爬虫的urllib.error.HTTPError: HTTP Error 418错误
  19. 医美分期一定会倒下一大片?
  20. java 气泡图_JavaScript图表库Highcharts入门教程(八):气泡图

热门文章

  1. 先导课程 单片机_单片机课程教案-课程教案
  2. 微软100题(91)智力题
  3. react-native打包release版本闪退
  4. 什么是Wildfly?
  5. 探究MFC之Dialog窗口最大化时控件自适应
  6. 算法面试必备-----贝壳算法面试准备
  7. 快速了解各种三维数字沙盘
  8. python告诉你迪丽热巴 vs 杨幂 vs 林志玲谁最美
  9. 关于CTC模型的理解
  10. 天猫商品详情接口,天猫商品优惠券接口,天猫api接口,天猫价格监控接口,天猫比价接口,品牌维权接口,天猫销量api接口,接口代码可对接数据分析业务,品牌维权,比价业务,行业分析业务接口代码分享