博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj 3533 [Sdoi2014]向量集 线段树+凸包+三分(+动态开数组) 好题
阅读量:4579 次
发布时间:2019-06-09

本文共 2183 字,大约阅读时间需要 7 分钟。

题目大意

维护一个向量集合,在线支持以下操作:

"A x y (|x|,|y| < =10^8)":加入向量(x,y);
"Q x y l r (|x|,|y| < =10^8,1 < =L < =R < =T,其中T为已经加入的向量个数)询问第L个到第R个加入的向量与向量(x,y)的点积的最大值。
集合初始时为空。

分析

题目中相当于给出一堆点\((z,w)\)

询问点\(x,y\)
\(maximize(ans=xz+yw)\)
\(\frac {ans} y=\frac x y z+w\)
\(w=-\frac x y z+\frac {ans} y\)
相当于函数\(w=f(z)=-\frac x y z+\frac {ans} y\)
就是一条斜率为\(-\frac x y\),截距为\(\frac {ans} y\)的线
对于一次询问中,斜率不变,截距记为\(D\)
①y>0,我们要使ans尽可能大,则截距尽可能大,答案在上凸壳
②y<0,我们要使ans尽可能大,则截距尽可能小,答案在下凸壳
③y=0,我们要使ans尽可能大,则xz尽可能大,z只会在最左最右,而最左最右的点一定在凸壳上,所以在上下凸壳找都行

做法

线段树维护凸包+三分

当然不能每插入一个点都合并一下
注意到一个没有插满的线段是不会被询问的
所以只有当插入位置为线段右端点时,将线段上的点搞一个凸包
每条线段合并一次,每条线段上有恰好\(r-l+1\)个点
所以每层n个点,凸包\(n\log n\),总共\(\log n\)
总复杂度\(n \log^2 n\)

注意

1.三分时要保证函数中没有重点,不然会有\(bug\)

2.\(ans\)可能为负,所以取\(max\)时的初始值为\(-INF\)
3.线段树大小为比\(n*2\)大的一个二进制数
4.数组大小为\(n*(\log n +1)+1\)

小结

扫描线的思维是找单调性,判断答案是否在凸包上的一种好方法

这种题只是说答案在凸包上,实际和凸包没有太大的关联
所以我们不必要先搞出询问区间的凸包再三分
只需要分段取出答案再取max就好了

solution

#include 
#include
#include
#include
#include
#include
typedef long long LL;using namespace std;const int M=1048576;const int N=10485763;const LL INF=9223372036854775807;LL rd(){ LL x=0;bool f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=0; for(;isdigit(c);c=getchar()) x=x*10+c-48; return f?x:-x;}struct pt{ LL x,y; pt (LL _x=0.0,LL _y=0.0){x=_x;y=_y;}};bool operator <(pt x,pt y){return (x.x!=y.x)?(x.x
1&&side(up[x].s[up[x].top-1],up[x].s[up[x].top],a[i])>=0) up[x].top--; up[x].s[++up[x].top]=a[i]; } dw[x].rsz(tp); for(i=1;i<=tp;i++){ while(dw[x].top>1&&side(dw[x].s[dw[x].top-1],dw[x].s[dw[x].top],a[i])<=0) dw[x].top--; dw[x].s[++dw[x].top]=a[i]; }}LL gmx(int x,pt d){ arr &nw=(d.y>0)?up[x]:dw[x]; int l=1,r=nw.top,m1,m2,i; LL tp1,tp2; while(r-l>=3){ m1=(l+l+r)/3; m2=(r+l+r)/3; tp1=dot(nw.s[m1],d); tp2=dot(nw.s[m2],d); if(tp1
>1; if(to<=mid) ins(x<<1,l,mid,to,d); else ins(x<<1|1,mid+1,r,to,d); addedge(x,d); if(r==to) convex(x);}LL get(int x,int l,int r,int tl,int tr,pt d){ if(tl<=l&&r<=tr) return gmx(x,d); int mid=l+r>>1; LL res=-INF; if(tl<=mid) res=max(res,get(x<<1,l,mid,tl,tr,d)); if(mid

转载于:https://www.cnblogs.com/acha/p/6477791.html

你可能感兴趣的文章
【SQL Server备份恢复】提高SQL Server备份速度
查看>>
移位操作的疑问
查看>>
gitlab 邮件服务器配置
查看>>
Python 循环语句(while, for)
查看>>
LinearGradient类来实现图片的渐变效果
查看>>
Golang关键字—— if/else
查看>>
PHP&MySQL(三)——数组
查看>>
GPS.NET 和 GeoFramework开源了
查看>>
汇编:采用址表的方法编写程序实现C程序的switch功能
查看>>
OFO和摩拜共享单车
查看>>
数据适配 DataAdapter对象
查看>>
有序列表ol和定义列表dl,dt,dd
查看>>
联想小新Air 15 安装黑苹果macOS High Sierra 10.13.6过程
查看>>
公共POI导出Excel方法–java
查看>>
次短路——Dijkstra
查看>>
Enter Query Mode Search Tricks Using Enter_Query Built-in in Oracle Forms
查看>>
Form属性、内置子程序、触发器、系统变量
查看>>
广州夜景一
查看>>
JVM(2)--一文读懂垃圾回收
查看>>
游戏开发——战斗系统设计技巧
查看>>