1. 程式人生 > >BZOJ 3533 [SDOI2014]向量集 (線段樹維護凸包)

BZOJ 3533 [SDOI2014]向量集 (線段樹維護凸包)

動態 持久化 pla www. cmp include geo style problem

題面:BZOJ傳送門 洛谷傳送門

容易想到這樣一個結論

把每次插入向量$(z,w)$改為在坐標系內插入一個點$(z,w)$,並對這些點建出凸包。

每次詢問向量$(x,y)$的答案,設一條直線$l$垂直於$(x,y)$,用l去切所有已知向量構成的凸包,第一個切到的點就是最優解,根據$y$的正負來決定是從上面切還是下面切

簡單證明一下,向量點積相當於向量$(z,w)$在$(x,y)$上的投影*$|(x,y)|$,所以要找在$(x,y)$方向上最長的向量。

我們對向量$(x,y)$所在的直線作垂線,假設垂線經過點$(z,w)$,並交$y$軸於一點$p$,那麽$p$點的縱坐標*向量$(x,y)$與$y$軸的夾角就是向量$(z,w)$的投影長,為了找最長的投影所以建凸包

然後就是維護凸包了,可題目要求強制在線,不能$CDQ$,詢問$[l,r]$區間的凸包且$x$無序,可持久化splay維護凸包?

維護可持久化凸包一般是用線段樹,線段樹每個區間都掛一個凸包,詢問$[l,r]$區間的凸包相當於區間查詢

如果保證x有序,每個新來的點在線段樹的每一層都插入,動態建出凸包。

所有詢問不會超出已知的凸包範圍!

每當線段樹的一個區間被插滿之後再建出凸包就行了。不會詢問沒建完的區間的凸包

每次在凸包上二分即可

時間$O(nlog^{2}n)$

  1 #include <cstdio>
  2 #include <cstring>
  3
#include <algorithm> 4 #define N1 400010 5 #define dd double 6 #define ll long long 7 using namespace std; 8 9 const ll inf=0x3f3f3f3f3f3f3f3fll; 10 const int zwz=1000000007; 11 int gint() 12 { 13 int ret=0,fh=1;char c=getchar(); 14 while(c<0||c>9){if(c==-)fh=-1
;c=getchar();} 15 while(c>=0&&c<=9){ret=ret*10+c-0;c=getchar();} 16 return ret*fh; 17 } 18 19 int n,Q; 20 ll X[N1],Y[N1]; 21 int pos[N1];//id[N1]; 22 int cmpx0(int x,int y){ if(X[x]!=X[y]) return X[x]<X[y]; else return Y[x]<Y[y];} 23 int cmpx1(int x,int y){ if(X[x]!=X[y]) return X[x]<X[y]; else return Y[x]>Y[y];} 24 struct OP{int x,y,l,r;}op[N1]; 25 ll ask(int i,ll x,ll y){ return X[i]*x+Y[i]*y; } 26 27 struct SEG{ 28 29 int stk0[20][N1],stk1[20][N1],ed0[N1<<2],ed1[N1<<2],que[N1]; 30 31 int cmp(int a,int b,ll x,ll y) 32 { 33 if(!a||!b) return a+b; 34 return (X[a]*y+Y[a]*(-x)>X[b]*y+Y[b]*(-x))?a:b; 35 } 36 37 void build0(int *s,int &tp,int l,int r) 38 { 39 int i,j; 40 for(i=l;i<=r;i++) que[i-l+1]=i; 41 sort(que+1,que+r-l+2,cmpx0); 42 for(j=1;j<=r-l+1;j++) 43 { 44 i=que[j]; 45 while(tp>1&&(Y[i]-Y[s[tp-1]])*(X[s[tp]]-X[s[tp-1]])>=(Y[s[tp]]-Y[s[tp-1]])*(X[i]-X[s[tp-1]])) 46 tp--; 47 s[++tp]=i; 48 } 49 } 50 int qup(int *s,int l,int r,int rt,ll x,ll y) 51 { 52 if(!ed0[rt]) build0(s,ed0[rt],l,r); 53 if(ed0[rt]==1) return s[1]; 54 l=2,r=ed0[rt]; int mid,ans=s[1]; 55 while(l<=r) 56 { 57 mid=(l+r)>>1; 58 if(1.0*(Y[s[mid]]-Y[s[mid-1]])/(X[s[mid]]-X[s[mid-1]])>=1.0*y/x) ans=s[mid],l=mid+1; 59 else r=mid-1; 60 } 61 return ans; 62 } 63 int qmax(int L,int R,int l,int r,int rt,int D,ll x,ll y) 64 { 65 if(L<=l&&r<=R) return qup(stk0[D]+l-1,l,r,rt,x,y); 66 int mid=(l+r)>>1,ans=0,tmp; 67 if(L<=mid) tmp=qmax(L,R,l,mid,rt<<1,D+1,x,y),ans=cmp(ans,tmp,x,y); 68 if(R>mid) tmp=qmax(L,R,mid+1,r,rt<<1|1,D+1,x,y),ans=cmp(ans,tmp,x,y); 69 return ans; 70 } 71 72 73 void build1(int *s,int &tp,int l,int r) 74 { 75 int i,j; 76 for(i=l;i<=r;i++) que[i-l+1]=i; 77 sort(que+1,que+r-l+2,cmpx1); 78 for(j=1;j<=r-l+1;j++) 79 { 80 i=que[j]; 81 while(tp>1&&(Y[i]-Y[s[tp-1]])*(X[s[tp]]-X[s[tp-1]])<=(Y[s[tp]]-Y[s[tp-1]])*(X[i]-X[s[tp-1]])) 82 tp--; 83 s[++tp]=i; 84 } 85 } 86 int qdown(int *s,int l,int r,int rt,ll x,ll y) 87 { 88 if(!ed1[rt]) build1(s,ed1[rt],l,r); 89 if(ed1[rt]==1) return s[1]; 90 l=2,r=ed1[rt]; int mid,ans=s[1]; 91 while(l<=r) 92 { 93 mid=(l+r)>>1; 94 if(1.0*(Y[s[mid]]-Y[s[mid-1]])/(X[s[mid]]-X[s[mid-1]])<=1.0*y/x) ans=s[mid],l=mid+1; 95 else r=mid-1; 96 } 97 return ans; 98 } 99 int qmin(int L,int R,int l,int r,int rt,int D,ll x,ll y) 100 { 101 if(L<=l&&r<=R) return qdown(stk1[D]+l-1,l,r,rt,x,y); 102 int mid=(l+r)>>1,ans=0,tmp; 103 if(L<=mid) tmp=qmin(L,R,l,mid,rt<<1,D+1,x,y),ans=cmp(ans,tmp,x,y); 104 if(R>mid) tmp=qmin(L,R,mid+1,r,rt<<1|1,D+1,x,y),ans=cmp(ans,tmp,x,y); 105 return ans; 106 } 107 108 }s; 109 ll ans; 110 void decode(int &x){ x=x^(ans&0x7fffffff); } 111 112 int de; 113 int main() 114 { 115 Q=gint(); char str[10],Str[10]; scanf("%s",Str); 116 int x,y,l,r,i,j,nn=0,a; 117 for(i=1;i<=Q;i++) 118 { 119 scanf("%s",str); 120 if(str[0]==A){ 121 op[i].x=gint(), op[i].y=gint(); nn++; pos[i]=nn; //id[nn]=i; 122 }else{ 123 op[i].x=gint(), op[i].y=gint(); 124 op[i].l=gint(), op[i].r=gint(); 125 } 126 } 127 for(i=1;i<=Q;i++) 128 { 129 x=op[i].x; y=op[i].y; l=op[i].l; r=op[i].r; 130 if(!l&&!r){ 131 if(Str[0]!=E) decode(x), decode(y); X[pos[i]]=x; Y[pos[i]]=y; 132 }else{ 133 if(Str[0]!=E) decode(x), decode(y), decode(l), decode(r); 134 if(y>0) a=s.qmax(l,r,1,nn,1,0,-y,x); 135 else a=s.qmin(l,r,1,nn,1,0,-y,x); 136 ans=X[a]*x+Y[a]*y; 137 printf("%lld\n",ans); 138 } 139 } 140 return 0; 141 }

BZOJ 3533 [SDOI2014]向量集 (線段樹維護凸包)