CF 678F Lena and Queries 线段树维护凸包+三分

题意:维护一个点集  向点集中进行插入删除和查询的操作  其中查询操作是 求 q*x+y的最大值 

设 z=q*x+y  得到 y=-q*x+z  显然我们需要使得截距z最大  我们需要维护一个凸包  然后在通过三分在凸包上找到最大值 

不过显然我们不能每次询问都去求一个凸包  那样复杂度是无法接受的 

我们可以维护每个点出现的时间  然后把它挂在线段树上面  最后在遍历一遍线段树就行了 (类似于线段树分治的思想) 

#include
using namespace std;
int n,xx;
const int N = 3e5+10;
int op[N],r[N],cnt;
bool emp[N];
typedef long long ll;
ll Q[N],ans[N];
const ll inf = 6e18;
struct Point{
	ll x,y;
	Point(){}
	Point(ll _x,ll _y){
		x=_x;y=_y;
	}
	bool operator < (const Point &b)const{
		if(x==b.x) return yT[N<<2];
#define pb push_back
ll cross(const Point &a,const Point &b){
	return a.x*b.y-a.y*b.x;
}
void update(int id,int l,int r,int L,int R,int v){
	if(L<=l&&R>=r){
		T[id].pb(p[v]);
		return;
	}
	int mid = l+r>>1;
	if(L<=mid) update(id<<1,l,mid,L,R,v);
	if(R>mid) update(id<<1|1,mid+1,r,L,R,v);
}
ll get(int id,const Point &a){
	return Q[id]*a.x+a.y;
}
void query(int id,int tp){
	int l=1,r=tp;
	while(r-l>=3){
		int mid1=(l+l+r)/3;
		int mid2=(l+r+r)/3;
		if(get(id,s[mid1])>1;
	if(l!=r){
		solve(id<<1,l,mid);
		solve(id<<1|1,mid+1,r);
	}
	if(!(int)T[id].size()) return;
	sort(T[id].begin(),T[id].end());
	int top=0; 
	for(auto v:T[id]){
		while(top>1&&cross(v-s[top-1],s[top]-s[top-1])<=0) top--;
		s[++top]=v;
	}
	for(int i = l; i <= r; i++){
		if(op[i]==3&&!emp[i])
		query(i,top);
	}
}
int main(){
	scanf("%d",&n);
	for(int i = 1; i <= n; i++){
		r[i]=n;
		scanf("%d",&op[i]);
		if(op[i]==1){
			p[i].in();
			cnt++;
		}else if(op[i]==2){
			scanf("%d",&xx);
			cnt--;r[xx]=i;
		}else{
			if(cnt==0) emp[i]=true;
			scanf("%lld",&Q[i]);
		}	
	}
	for(int i = 1; i <= n; i++){
		ans[i]=-inf;
		if(op[i]==1){
			update(1,1,n,i,r[i],i);
		}	
	}
	solve(1,1,n);
	for(int i = 1; i <= n; i++){
		if(op[i]==3){
			if(emp[i]) puts("EMPTY SET");
			else printf("%lld\n",ans[i]);
		}
	}
	return 0;
} 

 

你可能感兴趣的:(线段树,三分,计算几何)