动态维护凸包的另一种方法

题意,二维加入一个点,删除一个点,动态维护左上凸壳大小。
朴素做法,时间线段树加动态凸包。
神仙做法
考虑对横轴建立线段树,每个节点保存左上凸壳大小以及最大值,合并左右区间时,再右区间中找到第一个比左边最大值大的位置,然后递归查右区间中左端点到该位置的凸壳大小。
时间复杂度\(O(nlog^2(n))\)

#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
const double eps=1e-11;
const int N=1e5+10;
struct node{
	int len;
	double mx;
}T[N<<3];
int fcmp(double x,double y){
	if (fabs(x-y)<eps) return 0;
	return (x>y?1:-1);
}
int fir(int ind,int l,int r,double mx){
//	cerr<<"fir"<<ind<<" "<<l<<" "<<r<<" "<<mx<<endl;
	if (l==r) return (fcmp(T[ind].mx,mx)>0?l:-1);
	int mid=(l+r)>>1;
	return ((fcmp(T[ind<<1].mx,mx)>0)?fir(ind<<1,l,mid,mx):fir(ind<<1|1,mid+1,r,mx));
}
int ask(int ind,int l,int r,int rr){
	//cerr<<"ask"<<ind<<" "<<l<<" "<<r<<" "<<rr<<endl;
	//Sleep(1000);
	if (l>rr) return 0;
	if (r<=rr) return T[ind].len;
	int mid=(l+r)>>1;
	if (rr<=mid) return ask(ind<<1,l,mid,rr);
	
	int pos=fir(ind<<1|1,mid+1,r,T[ind<<1].mx);
	if (pos==-1) return T[ind<<1].len;
	else return T[ind<<1].len+ask(ind<<1|1,mid+1,r,rr)-ask(ind<<1|1,mid+1,r,pos-1);
}
void build(int ind,int l,int r){
	T[ind].len=0;
	T[ind].mx=0;
	if (l==r){
		return;
	}
	int mid=(l+r)>>1;
	build(ind<<1,l,mid);
	build(ind<<1|1,mid+1,r);
}
void modify(int ind,int l,int r,int p,double val){
	//cerr<<"modify"<<ind<<" "<<l<<" "<<r<<" "<<p<<" "<<val<<endl;
	if (l==r){
		T[ind].len=1;
		T[ind].mx=val;
		return;
	}
	int mid=(l+r)>>1;
	if (p<=mid) modify(ind<<1,l,mid,p,val);
	else modify(ind<<1|1,mid+1,r,p,val);
	
	T[ind].mx=max(T[ind<<1].mx,T[ind<<1|1].mx);
	int pos=fir(ind<<1|1,mid+1,r,T[ind<<1].mx);
	//cerr<<"pos"<<pos<<endl;
	if (pos==-1) T[ind].len=T[ind<<1].len;
	else T[ind].len=T[ind<<1].len+T[ind<<1|1].len-ask(ind<<1|1,mid+1,r,pos-1);
	//cerr<<"len"<<ind<<" "<<T[ind].len<<endl;
}
int n,m;
int main(){
	//freopen("1012.in","r",stdin);
	//freopen("1012.out","w",stdout); 
	int ca;
	scanf("%d",&ca);
	while (ca--){
		scanf("%d%d",&n,&m);
		build(1,1,n);
		for (int i=1; i<=m; ++i){
			//cerr<<"I"<<i<<endl;
			int id;
			double height;
			scanf("%d%lf",&id,&height);
			height/=id;
			//cerr<<"height"<<height<<endl;
			modify(1,1,n,id,height);
			cout<<T[1].len<<'\n';
		}
	}
}
/*
2
3 4
2 4
3 6
1 1000000000
1 1

3 4
2 4
3 6
1 1000000000
1 1
*/
posted @ 2020-10-29 00:03  Yuhuger  阅读(315)  评论(1编辑  收藏  举报