解法:时间线段树+凸包+三分
一开始本来想的是:cdq分治+李超线段树(因为之前学长在湘潭ccpc的时候给我嘴过一个类似的)
后来发现我的做法要对于每个分治区间开一棵李超线段树肯定mle
以时间为轴建立线段树,表示某个点(x,y)存在的时间
对于线段树的每个节点上的若干(x,y)维护一个上凸壳;
对于每个询问,从根一路访问到所在的叶子节点,对于途中每经过的一个节点,在其上的凸壳上三分一个最大值来更新ans;
访问完若ans=-inf则说明该询问之前没有加点,输出EMPTY SET,否则ans就是答案
注意:
1.叉积会爆longlong,要用double存
2.ans的初值应该赋值成-2e18,因为最后可行的ans会是-1e18
3.三分的暴力区间不能过小(开始赋了5,wa到怀疑人生)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <map> #include <cstring> #include <string> #include <vector> #define lch a[n].lc #define rch a[n].rc #define pb push_back #define er pop_back using namespace std; const long long inf=2e18; const int maxn=500010; int n,root,topt,nt[maxn],sx,sy; long long ans; struct da{int lc,rc;}a[4*maxn]; struct qu{int op;long long x,y;}q[maxn]; vector<int>now[4*maxn]; vector<int>tu[4*maxn]; bool cmp(int aa,int bb) { if ((double)(q[aa].y-sy)*(q[bb].x-sx)==(double)(q[bb].y-sy)*(q[aa].x-sx)) return abs(q[aa].x-sx)<abs(q[bb].x-sx); return (double)(q[aa].y-sy)*(q[bb].x-sx)<(double)(q[bb].y-sy)*(q[aa].x-sx); } void build_tree(int &n,int l,int r) { n=++topt; if (l==r) return ; int mid=(l+r)>>1; build_tree(lch,l,mid); build_tree(rch,mid+1,r); } void tree_add(int n,int L,int R,int l,int r,int k) { if (L==l && R==r) {now[n].pb(k); return ;} int mid=(L+R)>>1; if (r<=mid) tree_add(lch,L,mid,l,r,k); else if (l>=mid+1) tree_add(rch,mid+1,R,l,r,k); else tree_add(lch,L,mid,l,mid,k),tree_add(rch,mid+1,R,mid+1,r,k); } bool cro(int a,int b,int c) {return (double)(q[c].y-q[b].y)*(q[b].x-q[a].x)<(double)(q[b].y-q[a].y)*(q[c].x-q[b].x);} void work(int n,int l,int r) { if (now[n].size()) { sy=1e9+10; for (auto i:now[n]) if (q[i].y<sy) {sx=q[i].x; sy=q[i].y;} sort(now[n].begin(),now[n].end(),cmp); int rr=-1; for (auto i:now[n]) { while (rr>=1 && cro(tu[n][rr-1],tu[n][rr],i)) tu[n].er(),rr--; tu[n].pb(i); rr++; } } if (l==r) return; int mid=(l+r)>>1; work(lch,l,mid); work(rch,mid+1,r); } long long calc(int n,long long kk) {return 1ll*q[n].x*kk+1ll*q[n].y;} void qury(int n,int l,int r,int lc,long long mul) { if (tu[n].size()) { int ll=0,rr=tu[n].size()-1; while (ll<=rr-20) { int lmid=ll+(rr-ll)/3; int rmid=rr-(rr-ll)/3; if (calc(tu[n][rmid],mul)>=calc(tu[n][lmid],mul)) {ll=lmid; ans=max(ans,calc(tu[n][rmid],mul));} else {rr=rmid; ans=max(ans,calc(tu[n][lmid],mul));} } for (int i=ll;i<=rr;i++) ans=max(ans,calc(tu[n][i],mul)); } if (l==r) return; int mid=(l+r)>>1; if (lc<=mid) qury(lch,l,mid,lc,mul);else qury(rch,mid+1,r,lc,mul); } int main() { scanf("%d",&n); for (int i=1;i<=n;i++) nt[i]=n; for (int i=1;i<=n;i++) { scanf("%d",&q[i].op); if (q[i].op==1) scanf("%lld%lld",&q[i].x,&q[i].y); else scanf("%lld",&q[i].x); if (q[i].op==2) nt[q[i].x]=i; } build_tree(root,1,n); for (int i=1;i<=n;i++) if (q[i].op==1) tree_add(root,1,n,i,nt[i],i); work(root,1,n); for (int i=1;i<=n;i++) if (q[i].op==3) { ans=-inf; qury(root,1,n,i,q[i].x); if (ans==-inf) printf("EMPTY SET\n");else printf("%lld\n",ans); } return 0; }