bzoj 3533 [Sdoi2014]向量集 线段树+凸包+三分(+动态开数组) 好题
2017-02-28 10:43
447 查看
题目大意
维护一个向量集合,在线支持以下操作:"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 <cstdio> #include <cstdlib> #include <cctype> #include <cstring> #include <cmath> #include <algorithm> 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<y.x):(x.y<y.y);} pt operator +(pt x,pt y){return pt(x.x+y.x,x.y+y.y);} pt operator -(pt x,pt y){return pt(x.x-y.x,x.y-y.y);} LL dot(pt x,pt y){return x.x*y.x+x.y*y.y;} LL det(pt x,pt y){return x.x*y.y-x.y*y.x;} LL side(pt x,pt y,pt z){return det(y-x,z-x);} LL n,lst,typ,ps; char s[7]; int g[M<<1],te; struct edge{pt y;int nxt;}e ; void addedge(int x,pt y){ e[++te].y=y;e[te].nxt=g[x];g[x]=te; } pt mempool ; int tot; struct arr{ pt *s;int top; void rsz(int n){ top=0; s=mempool+tot+1; tot+=n+1; } }up[M<<1],dw[M<<1]; pt a[M]; LL decode(LL x){ if(typ) return x^(lst&0x7fffffff); return x; } void convex(int x){ int p,tp=0,i; for(p=g[x];p;p=e[p].nxt) a[++tp]=e[p].y; sort(a+1,a+tp+1); up[x].rsz(tp); for(i=1;i<=tp;i++){ while(up[x].top>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<tp2) l=m1; else r=m2; } LL ans=-INF; for(i=l;i<=r;i++) ans=max(ans,dot(nw.s[i],d)); return ans; } void ins(int x,int l,int r,int to,pt d){ if(l==r){ up[x].rsz(1);dw[x].rsz(1); up[x].top=dw[x].top=1; up[x].s[1]=dw[x].s[1]=d; return; } int mid=l+r>>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<tr) res=max(res,get(x<<1|1,mid+1,r,tl,tr,d)); return res; } int main(){ n=rd();scanf("%s",s); if(s[0]!='E') typ=1; else typ=0; int i; LL x,y,L,R; for(i=1;i<=n;i++){ scanf("%s",s); if(s[0]=='A'){ ++ps; x=decode(rd()); y=decode(rd()); pt p=pt(x,y); ins(1,1,n,ps,p); } else{ x=decode(rd()); y=decode(rd()); L=decode(rd()); R=decode(rd()); pt p=pt(x,y); lst=get(1,1,n,L,R,p); printf("%lld\n",lst); } } return 0; }
相关文章推荐
- Bzoj3533:[Sdoi2014]向量集:线段树+凸包+三分
- BZOJ 3533 Sdoi2014 向量集 线段树+凸包+三分
- [Sdoi 2014] bzoj3533 向量集 [线段树+凸包+三分]
- 【BZOJ】【P3533】【Sdoi2014】【向量集】【题解】【线段树+凸包+三分】
- bzoj 3533: [Sdoi2014]向量集 线段树+凸包+二分
- BZOJ3533 [Sdoi2014]向量集 【线段树 + 凸包 + 三分】
- BZOJ 3533: [Sdoi2014]向量集( 线段树 + 三分 )
- 【bzoj3533】[Sdoi2014]向量集 三分+线段树+凸包
- bzoj3533: [Sdoi2014]向量集
- 【SDOI2014】【BZOJ3533】向量集
- bzoj 3529: [Sdoi2014]数表 莫比乌斯反演&树状数组
- 【bzoj3513】【SDOI2014】【旅行】【树链剖分+动态开点】
- |BZOJ 3531|树链剖分|动态开点线段树|[Sdoi2014]旅行
- 【bzoj3531】 [SDOI2014]旅行 树链剖分+动态开点线段树
- bzoj 3529: [Sdoi2014]数表 莫比乌斯反演+树状数组
- BZOJ 3531: [Sdoi2014]旅行【树剖+动态开点线段树【听说有人写平衡树?【滑稽
- [莫比乌斯反演+数状数组] BZOJ3529: [Sdoi2014]数表
- bzoj 3533 [Sdoi2014]向量集 凸包
- 【bzoj3529】【SDOI2014】【数表】【莫比乌斯反演+树状数组】
- BZOJ3533: [Sdoi2014]向量集