动态维护凸包的另一种方法
题意,二维加入一个点,删除一个点,动态维护左上凸壳大小。
朴素做法,时间线段树加动态凸包。
神仙做法
考虑对横轴建立线段树,每个节点保存左上凸壳大小以及最大值,合并左右区间时,再右区间中找到第一个比左边最大值大的位置,然后递归查右区间中左端点到该位置的凸壳大小。
时间复杂度\(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
*/