题目
和二分图不同的是:1. 没办法回退。。 2.就算回退了 也不能快速与其他修改连成关系,不同于并查集。因为要与之前的这个节点的修改 按横坐标排序 构造凸壳。
就需要一段一段的被更新。
先把每个向量存在的时间段插入到时间线段树中。然后答案的更新被分成好多部分更新。每到线段树一个节点,用这个节点存在的向量的构成上凸壳(可以画画图就是对的),然后这个节点对应时间段里的查询 在这个凸壳上三分更新答案。这样一定不会遗忘掉。。比如时间 i 的询问 q[i]那么对他影响的修改的[t1,t2]
t1<=i<=t2 那么 t1一定在其中一个 这个修改在线段树分段 中。就会被query…
#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=2e5+5;
struct Update{int x,y;}u[N];
int tim[N];
struct Query{int x,y;}q[N];
vector<int>vec[N<<2];
void ins(int id,int cl,int cr,int l,int r,int pos){
if(cl<=l&&r<=cr) {vec[pos].push_back(id);return;}
int mid=(l+r)>>1;
if(cl<=mid) ins(id,cl,cr,l,mid,pos<<1);
if(cr>mid) ins(id,cl,cr,mid+1,r,pos<<1|1);
}
inline int cmp(int id1,int id2){//注意x相同时y小的在前面
return (u[id1].x==u[id2].x)?(u[id1].y<=u[id2].y):(u[id1].x<=u[id2].x);
}
inline ll cal(int i,int j,int k){//维护斜率递减的上凸壳
return (ll)(u[k].y-u[i].y)*(u[j].x-u[i].x)>(ll)(u[j].y-u[i].y)*(u[k].x-u[i].x);
}
inline ll dj(int i,int j){//i j两点对应的点积 注意i是询问q数组 j是修改的,用来更新询问 是u数组
return ((ll)q[i].x*u[j].x)+((ll)u[j].y*q[i].y);
}
int st[N];ll ans[N];
inline void query(int id,int top){//在凸壳上三分
int low=1,high=top,mid1,mid2;
while(high-low>=3){
mid1=low+(high-low)/3,mid2=high-(high-low)/3;
if(dj(id,st[mid1])<=dj(id,st[mid2])) low=mid1;
else high=mid2;
}
for(int i=low;i<=high;++i) ans[id]=max(ans[id],dj(id,st[i]));
}
void divide(int l,int r,int pos){
sort(vec[pos].begin(),vec[pos].end(),cmp);//为了构造上凸壳
int top=0;
for(int i=0;i<vec[pos].size();++i){
int d=vec[pos][i];
while(top>=2&&cal(st[top-1],st[top],d)) --top;
st[++top]=d;
}
for(int i=l;i<=r;++i)
if(q[i].x) query(i,top);//时间在[l,r]的查询都需要被上述凸壳更新 因为上面的凸壳在时间[l,r]一直存在
if(l==r) return;
int mid=(l+r)>>1;
divide(l,mid,pos<<1),divide(mid+1,r,pos<<1|1);
}
int main(){
int n;scanf("%d",&n);
int tot=0;
for(int i=1;i<=n;++i){
int f;scanf("%d",&f);
if(f==1) ++tot,scanf("%d%d",&u[tot].x,&u[tot].y),tim[tot]=i;
if(f==2){
int d;scanf("%d",&d);//删除第d个添加进来的
ins(d,tim[d],i,1,n,1),tim[d]=0;
}
if(f==3) scanf("%d%d",&q[i].x,&q[i].y);
}
for(int i=1;i<=tot;++i)
if(tim[i]) ins(i,tim[i],n,1,n,1);
divide(1,n,1);
for(int i=1;i<=n;++i)
if(q[i].x) printf("%lld\n",ans[i]);
}