bzoj4311向量(线段树分治+斜率优化)
第二道线段树分治。
首先设当前向量是(x,y),剩余有两个不同的向量(u1,v1)(u2,v2),假设u1>u2,则移项可得,若(u1,v1)优于(u2,v2),则-x/y>(v1-v2)/(u1-u2),然后维护上凸壳后进行三分即可,复杂度O(nlog2n),如果将询问排序扫一遍,可以优化到O(nlogn),当然我没写。
#include<bits/stdc++.h> #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 using namespace std; typedef long long ll; const int N=2e5+7; struct node{int x,y,l,r;}p[N],q[N]; int n,tim,tot,top; ll ans[N]; vector<node>a[N<<2]; node st[N]; bool cmp(node a,node b){return a.x==b.x?a.y<b.y:a.x<b.x;} ll dot(node a,node b){return 1ll*a.x*b.x+1ll*a.y*b.y;} ll cross(node a,node b,node c){return 1ll*(a.x-c.x)*(b.y-c.y)-1ll*(a.y-c.y)*(b.x-c.x);} void update(int L,int R,int id,int l,int r,int rt) { if(L<=l&&r<=R){a[rt].push_back(p[id]);return;} int mid=l+r>>1; if(L<=mid)update(L,R,id,lson); if(R>mid)update(L,R,id,rson); } ll query(int id) { int l=1,r=top,m1,m2; ll ret=0; while(r-l>=3) { m1=l+(r-l)/3,m2=r-(r-l)/3; if(dot(q[id],st[m1])<=dot(q[id],st[m2]))l=m1;else r=m2; } for(int i=l;i<=r;i++)ret=max(ret,dot(q[id],st[i])); return ret; } void work(int x,int l,int r) { if(!a[x].size())return; top=0; sort(a[x].begin(),a[x].end(),cmp); for(int i=0;i<a[x].size();i++) { while(top>1&&cross(st[top-1],st[top],a[x][i])>=0)top--; st[++top]=a[x][i]; } for(int i=l;i<=r;i++)ans[i]=max(ans[i],query(i)); } void divide(int l,int r,int rt) { work(rt,l,r); if(l==r)return; int mid=l+r>>1;divide(lson),divide(rson); } int main() { scanf("%d",&n); for(int i=1,op,x,y;i<=n;i++) { scanf("%d%d",&op,&x); if(op==1)scanf("%d",&y),p[++tot]=(node){x,y,tim+1,-1}; else if(op==2)p[x].r=tim; else scanf("%d",&y),q[++tim]=(node){x,y,tim,tim}; } for(int i=1;i<=tot;i++)if(p[i].r==-1)p[i].r=tim; for(int i=1;i<=tot;i++)if(p[i].l<=p[i].r)update(p[i].l,p[i].r,i,1,tim,1); divide(1,tim,1); for(int i=1;i<=tim;i++)printf("%lld\n",ans[i]); }