好像没什么好说的,记录每个点进出的时刻,每个点对应线段树上的O(logn)个节点,然后按时间分治就可以了。
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<iostream> #include<vector> #define maxn 200010 using namespace std; struct yts1 { long long x,y; }p[maxn],st[maxn],tmp[maxn]; struct yts { int l,r; vector<yts1> v; }t[4*maxn]; struct yts2 { long long x,y,ans; }q[maxn]; int n,m,L[maxn],tot,top; long long operator^ (yts1 a,yts1 b) { return a.x*b.y-a.y*b.x; } long long operator* (yts1 a,yts1 b) { return a.x*b.x+a.y*b.y; } bool operator< (yts1 a,yts1 b) { return a.x<b.x || (a.x==b.x && a.y<b.y); } yts1 operator-(yts1 a,yts1 b) { yts1 ans; ans.x=a.x-b.x;ans.y=a.y-b.y; return ans; } void build(int i,int l,int r) { t[i].l=l;t[i].r=r; if (l==r) return; int mid=(l+r)/2; build(i*2,l,mid);build(i*2+1,mid+1,r); } void insert(int i,int l,int r,int x) { if (l<=t[i].l && t[i].r<=r) { t[i].v.push_back(p[x]);return; } int mid=(t[i].l+t[i].r)/2; if (l<=mid) insert(i*2,l,r,x); if (mid<r) insert(i*2+1,l,r,x); } void query(int i) { if (!top) return; yts1 o; o.x=q[i].x;o.y=q[i].y; int l=1,r=top; while (r-l>=3) { int mid=l+(r-l)/3,midmid=r-(r-l)/3; if ((o*st[mid])>(o*st[midmid])) r=midmid; else l=mid; } for (int j=l;j<=r;j++) q[i].ans=max(q[i].ans,o*st[j]); } void solve(int x,int l,int r) { int mid=(l+r)/2; if (l<r) solve(x*2,l,mid),solve(x*2+1,mid+1,r); top=0; sort(t[x].v.begin(),t[x].v.end()); for (int i=0;i<t[x].v.size();i++) { while (top>1 && ((t[x].v[i]-st[top])^(st[top]-st[top-1]))<=0) top--; st[++top]=t[x].v[i]; } for (int i=l;i<=r;i++) if (q[i].x) query(i); } int main() { scanf("%d",&n); build(1,1,n); for (int i=1;i<=n;i++) { int opt; long long x,y; scanf("%d",&opt); if (opt==1) {scanf("%lld%lld",&x,&y);p[++tot].x=x,p[tot].y=y,L[tot]=i;} if (opt==2) {scanf("%lld",&x);insert(1,L[x],i,x);L[x]=0;} if (opt==3) scanf("%lld%lld",&q[i].x,&q[i].y); } for (int i=1;i<=tot;i++) if (L[i]) insert(1,L[i],n,i); solve(1,1,n); for (int i=1;i<=n;i++) if (q[i].x) printf("%lld\n",q[i].ans); return 0; }