[BZOJ4311]向量(凸包+三分+线段树分治)
可以发现答案一定在所有向量终点形成的上凸壳上,于是在上凸壳上三分即可。
对于删除操作,相当于每个向量有一个作用区间,线段树分治即可。$O(n\log^2 n)$
同时可以发现,当询问按斜率排序后,每个凸壳上的决策点也是单调变化的,于是可以记录每次的决策位置。$O(n\log n)$
$O(n\log^2 n)$:
1 #include<cstdio> 2 #include<vector> 3 #include<cstring> 4 #include<algorithm> 5 #define ls (x<<1) 6 #define rs (ls|1) 7 #define lson ls,L,mid 8 #define rson rs,mid+1,R 9 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 10 typedef long long ll; 11 using namespace std; 12 13 const int N=200010; 14 int n,op,x,y,tim,tot,d[N<<2]; 15 struct P{ ll x,y; }; 16 struct D{ int l,r; P p; }p[N],q[N]; 17 vector<P>v[N<<2]; 18 P operator -(P a,P b){ return (P){a.x-b.x,a.y-b.y}; } 19 ll operator *(P a,P b){ return a.x*b.y-a.y*b.x; } 20 bool cmp1(const D &a,const D &b){ return (a.p.x==b.p.x) ? a.p.y<b.p.y : a.p.x<b.p.x; } 21 bool cmp2(const D &a,const D &b){ return a.p*b.p<0; } 22 ll calc(P a,P b){ return a.x*b.x+a.y*b.y; } 23 24 void ins(int x,int L,int R,int l,int r,P p){ 25 if (l<=L && R<=r){ 26 while (v[x].size()>1 && (v[x][v[x].size()-1]-v[x][v[x].size()-2])*(p-v[x][v[x].size()-2])>=0) v[x].pop_back(); 27 v[x].push_back(p); return; 28 } 29 int mid=(L+R)>>1; 30 if (l<=mid) ins(lson,l,r,p); 31 if (r>mid) ins(rson,l,r,p); 32 } 33 34 ll que(int x,int L,int R,int pos,P p){ 35 ll ans=0; 36 if (v[x].size()){ 37 int l=0,r=v[x].size()-1; 38 while (l+2<r){ 39 int m1=l+(r-l)/3,m2=r-(r-l)/3; 40 if (calc(p,v[x][m1])>calc(p,v[x][m2])) r=m2; else l=m1; 41 } 42 rep(i,l,r) ans=max(ans,calc(p,v[x][i])); 43 } 44 if (L==R) return ans; 45 int mid=(L+R)>>1; 46 if (pos<=mid) return max(ans,que(lson,pos,p)); else return max(ans,que(rson,pos,p)); 47 } 48 49 int main(){ 50 freopen("bzoj4311.in","r",stdin); 51 freopen("bzoj4311.out","w",stdout); 52 scanf("%d",&n); 53 rep(i,1,n){ 54 scanf("%d",&op); 55 if (op==1) scanf("%d%d",&x,&y),p[++tim]=(D){i,n,x,y}; 56 if (op==2) scanf("%d",&x),p[x].r=i; 57 if (op==3) scanf("%d%d",&x,&y),q[++tot]=(D){i,tot,x,y}; 58 } 59 sort(p+1,p+tim+1,cmp1); 60 rep(i,1,tim) ins(1,1,n,p[i].l,p[i].r,p[i].p); 61 rep(i,1,tot) printf("%lld\n",que(1,1,n,q[i].l,q[i].p)); 62 return 0; 63 }
$O(n\log n)$
1 #include<cstdio> 2 #include<vector> 3 #include<cstring> 4 #include<algorithm> 5 #define ls (x<<1) 6 #define rs (ls|1) 7 #define lson ls,L,mid 8 #define rson rs,mid+1,R 9 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 10 typedef long long ll; 11 using namespace std; 12 13 const int N=200010; 14 ll ans[N]; 15 int n,op,x,y,tim,tot,d[N<<2]; 16 struct P{ ll x,y; }; 17 struct D{ int l,r; P p; }p[N],q[N]; 18 vector<P>v[N<<2]; 19 P operator -(P a,P b){ return (P){a.x-b.x,a.y-b.y}; } 20 ll operator *(P a,P b){ return a.x*b.y-a.y*b.x; } 21 bool cmp1(const D &a,const D &b){ return (a.p.x==b.p.x) ? a.p.y<b.p.y : a.p.x<b.p.x; } 22 bool cmp2(const D &a,const D &b){ return a.p*b.p<0; } 23 ll calc(P a,P b){ return a.x*b.x+a.y*b.y; } 24 25 void ins(int x,int L,int R,int l,int r,P p){ 26 if (l<=L && R<=r){ 27 while (v[x].size()>1 && (v[x][v[x].size()-1]-v[x][v[x].size()-2])*(p-v[x][v[x].size()-2])>=0) v[x].pop_back(); 28 v[x].push_back(p); return; 29 } 30 int mid=(L+R)>>1; 31 if (l<=mid) ins(lson,l,r,p); 32 if (r>mid) ins(rson,l,r,p); 33 } 34 35 ll que(int x,int L,int R,int pos,P p){ 36 ll ans=0; 37 if (v[x].size()){ 38 while (d[x]<(int)v[x].size()-1 && calc(p,v[x][d[x]+1])>=calc(p,v[x][d[x]])) d[x]++; 39 ans=calc(p,v[x][d[x]]); 40 } 41 if (L==R) return ans; 42 int mid=(L+R)>>1; 43 if (pos<=mid) return max(ans,que(lson,pos,p)); else return max(ans,que(rson,pos,p)); 44 } 45 46 int main(){ 47 freopen("bzoj4311.in","r",stdin); 48 freopen("bzoj4311.out","w",stdout); 49 scanf("%d",&n); 50 rep(i,1,n){ 51 scanf("%d",&op); 52 if (op==1) scanf("%d%d",&x,&y),p[++tim]=(D){i,n,x,y}; 53 if (op==2) scanf("%d",&x),p[x].r=i; 54 if (op==3) scanf("%d%d",&x,&y),q[++tot]=(D){i,tot,x,y}; 55 } 56 sort(p+1,p+tim+1,cmp1); 57 rep(i,1,tim) ins(1,1,n,p[i].l,p[i].r,p[i].p); 58 sort(q+1,q+tot+1,cmp2); 59 rep(i,1,tot) ans[q[i].r]=que(1,1,n,q[i].l,q[i].p); 60 rep(i,1,tot) printf("%lld\n",ans[i]); 61 return 0; 62 }