容易想到这样一个结论
把每次插入向量$(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 }