[BZOJ4311]向量(凸包+三分+线段树分治)

时间:2023-03-09 22:31:51
[BZOJ4311]向量(凸包+三分+线段树分治)

可以发现答案一定在所有向量终点形成的上凸壳上,于是在上凸壳上三分即可。

对于删除操作,相当于每个向量有一个作用区间,线段树分治即可。$O(n\log^2 n)$

同时可以发现,当询问按斜率排序后,每个凸壳上的决策点也是单调变化的,于是可以记录每次的决策位置。$O(n\log n)$

$O(n\log^2 n)$:

 #include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define ls (x<<1)
#define rs (ls|1)
#define lson ls,L,mid
#define rson rs,mid+1,R
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=;
int n,op,x,y,tim,tot,d[N<<];
struct P{ ll x,y; };
struct D{ int l,r; P p; }p[N],q[N];
vector<P>v[N<<];
P operator -(P a,P b){ return (P){a.x-b.x,a.y-b.y}; }
ll operator *(P a,P b){ return a.x*b.y-a.y*b.x; }
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; }
bool cmp2(const D &a,const D &b){ return a.p*b.p<; }
ll calc(P a,P b){ return a.x*b.x+a.y*b.y; } void ins(int x,int L,int R,int l,int r,P p){
if (l<=L && R<=r){
while (v[x].size()> && (v[x][v[x].size()-]-v[x][v[x].size()-])*(p-v[x][v[x].size()-])>=) v[x].pop_back();
v[x].push_back(p); return;
}
int mid=(L+R)>>;
if (l<=mid) ins(lson,l,r,p);
if (r>mid) ins(rson,l,r,p);
} ll que(int x,int L,int R,int pos,P p){
ll ans=;
if (v[x].size()){
int l=,r=v[x].size()-;
while (l+<r){
int m1=l+(r-l)/,m2=r-(r-l)/;
if (calc(p,v[x][m1])>calc(p,v[x][m2])) r=m2; else l=m1;
}
rep(i,l,r) ans=max(ans,calc(p,v[x][i]));
}
if (L==R) return ans;
int mid=(L+R)>>;
if (pos<=mid) return max(ans,que(lson,pos,p)); else return max(ans,que(rson,pos,p));
} int main(){
freopen("bzoj4311.in","r",stdin);
freopen("bzoj4311.out","w",stdout);
scanf("%d",&n);
rep(i,,n){
scanf("%d",&op);
if (op==) scanf("%d%d",&x,&y),p[++tim]=(D){i,n,x,y};
if (op==) scanf("%d",&x),p[x].r=i;
if (op==) scanf("%d%d",&x,&y),q[++tot]=(D){i,tot,x,y};
}
sort(p+,p+tim+,cmp1);
rep(i,,tim) ins(,,n,p[i].l,p[i].r,p[i].p);
rep(i,,tot) printf("%lld\n",que(,,n,q[i].l,q[i].p));
return ;
}

$O(n\log n)$

 #include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define ls (x<<1)
#define rs (ls|1)
#define lson ls,L,mid
#define rson rs,mid+1,R
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=;
ll ans[N];
int n,op,x,y,tim,tot,d[N<<];
struct P{ ll x,y; };
struct D{ int l,r; P p; }p[N],q[N];
vector<P>v[N<<];
P operator -(P a,P b){ return (P){a.x-b.x,a.y-b.y}; }
ll operator *(P a,P b){ return a.x*b.y-a.y*b.x; }
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; }
bool cmp2(const D &a,const D &b){ return a.p*b.p<; }
ll calc(P a,P b){ return a.x*b.x+a.y*b.y; } void ins(int x,int L,int R,int l,int r,P p){
if (l<=L && R<=r){
while (v[x].size()> && (v[x][v[x].size()-]-v[x][v[x].size()-])*(p-v[x][v[x].size()-])>=) v[x].pop_back();
v[x].push_back(p); return;
}
int mid=(L+R)>>;
if (l<=mid) ins(lson,l,r,p);
if (r>mid) ins(rson,l,r,p);
} ll que(int x,int L,int R,int pos,P p){
ll ans=;
if (v[x].size()){
while (d[x]<(int)v[x].size()- && calc(p,v[x][d[x]+])>=calc(p,v[x][d[x]])) d[x]++;
ans=calc(p,v[x][d[x]]);
}
if (L==R) return ans;
int mid=(L+R)>>;
if (pos<=mid) return max(ans,que(lson,pos,p)); else return max(ans,que(rson,pos,p));
} int main(){
freopen("bzoj4311.in","r",stdin);
freopen("bzoj4311.out","w",stdout);
scanf("%d",&n);
rep(i,,n){
scanf("%d",&op);
if (op==) scanf("%d%d",&x,&y),p[++tim]=(D){i,n,x,y};
if (op==) scanf("%d",&x),p[x].r=i;
if (op==) scanf("%d%d",&x,&y),q[++tot]=(D){i,tot,x,y};
}
sort(p+,p+tim+,cmp1);
rep(i,,tim) ins(,,n,p[i].l,p[i].r,p[i].p);
sort(q+,q+tot+,cmp2);
rep(i,,tot) ans[q[i].r]=que(,,n,q[i].l,q[i].p);
rep(i,,tot) printf("%lld\n",ans[i]);
return ;
}