bzoj2300 [HAOI2011]防线修建 离线凸包

这个题可以在线做,splay维护凸包的同时维护区间最值线段树,当删除一个点就找跨过这个点的不在凸包上的点的y最值,然后分下去

由于一次确定一个点,所以复杂度还是nlogn的,只是比较难写

如果一个操作非常麻烦,可以考虑对立面,所以就可以考虑倒着加点,就可以直接用splay维护了

注:

引用函数注意对应关系

注意=号


码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int op[100005][2],lll,rrr,sz[100005],ch[100005][2],fu[100005],i,j,n,m,Q,rt,tot,sta[100005],top,dui[100005];
double daan[100005],ans,x[100005],y[100005];
bool wu[100005];
struct dian
{
	double x,y;
	int id;
}D[100005];
void up(int o)
{
	sz[o]=sz[ch[o][0]]+sz[ch[o][1]]+1;
}
void set(int o,int wh,int child)
{
	ch[o][wh]=child;
	if(child)fu[child]=o;
	up(o);
}
int getwh(int o)
{
	return ch[fu[o]][0]==o?0:1;	
}
void rotate(int o)
{
	int fa=fu[o];
	int ye=fu[fa];
	int wh=getwh(o);
	set(fa,wh,ch[o][wh^1]);
	set(o,wh^1,fa);
	fu[o]=ye;
	if(ye)ch[ye][ch[ye][0]==fa?0:1]=o;	
}
void splay(int o,int tar)
{
	for(;fu[o]!=tar;rotate(o))
	if(fu[fu[o]]!=tar)
	getwh(o)==getwh(fu[o])?rotate(fu[o]):rotate(o);
	if(tar==0)rt=o;	
}
void dfs(int o)
{
	if(o==0)return;
	cout<<"'"<<x[o]<<" "<<y[o]<<"'"<<"(";
	dfs(ch[o][0]);cout<<",";
	dfs(ch[o][1]);
	cout<<")";
}
void del(int o)
{
	splay(o,0);
	if(ch[o][0]==0)
	{
		rt=ch[o][1];
		fu[ch[o][1]]=0;	
	}
	else 
	if(ch[o][1]==0)
	{
	    rt=ch[o][0];
	    fu[ch[o][0]]=0;
	}
	else
	{
		int p=ch[o][0];
		while(ch[p][1])p=ch[p][1];
		set(p,1,ch[o][1]);
		fu[ch[o][0]]=0;
		splay(p,0);		
	}
}
int xin(int X,int Y)
{
	int o=++tot;
	x[o]=X;
	y[o]=Y;
	sz[o]=1;
	return o;
}
double xl(double ax,double ay,double bx,double by)
{if(ax==bx)return -9999999999999; 
	return (ay-by)/(ax-bx);
}
double jl(double ax,double ay,double bx,double by)
{
	return sqrt((ax-bx)*(ax-bx)+(ay-by)*(ay-by));
}
int jian(int l,int r)
{
	if(l>r)return 0;
	int mid=(l+r)>>1,o=++tot;
	x[o]=D[sta[mid]].x;
	y[o]=D[sta[mid]].y;
	set(o,0,jian(l,mid-1));
	set(o,1,jian(mid+1,r));
	return o;		
}
bool cmp(dian a,dian b)
{
	if(a.x==b.x)return a.y<b.y;
	return a.x<b.x;
}
void tubao()
{
	sort(D+1,D+1+n,cmp);
	for(i=1;i<=n;i++)
	dui[D[i].id]=i;
	int i;
	for(i=1;i<=n;i++)
	{
		if(wu[D[i].id])continue;
		while(top>=2&&xl(D[i].x,D[i].y,D[sta[top-1]].x,D[sta[top-1]].y)>=xl(D[sta[top-1]].x,D[sta[top-1]].y,D[sta[top]].x,D[sta[top]].y))top--;
		sta[++top]=i;	
	}	
	for(i=1;i<=top;i++)	
	{
	ans+=jl(D[sta[i]].x,D[sta[i]].y,D[sta[i-1]].x,D[sta[i-1]].y);		
	}
	rt=jian(1,top);	
}
int xiao(double X)
{
	 int o=rt,last=0,ll=0;
             while(o)
             {last=o;
             if(x[o]<X&&(x[o]>x[ll]||ll==0))ll=o;
             	if(x[o]<X)o=ch[o][1];
             	else o=ch[o][0];
			 }
	splay(last,0);
	return ll; 
}
int da(double X)
{
		 int o=rt,last=0,rr=0;
             while(o)
             {last=o;
             if(x[o]>X&&(x[o]<x[rr]||rr==0))rr=o;
             	if(x[o]<=X)o=ch[o][1];
             	else o=ch[o][0];
			 }
	splay(last,0);
	return rr; 
}
int main()
{
scanf("%d",&m);
	scanf("%lf%lf",&D[0].x,&D[0].y);
	scanf("%d",&n);
	for(i=1;i<=n;i++)
{
scanf("%lf%lf",&D[i].x,&D[i].y);
D[i].id=i;	
}	
D[++n].x=D[0].x;D[n].y=D[0].y;D[n].id=n;
D[++n].x=0;D[n].y=0;D[n].id=n;
D[++n].x=m;D[n].y=0;D[n].id=n;
D[0].x=D[0].y=D[0].id=0;
	scanf("%d",&Q);
	for(i=1;i<=Q;i++)
	{scanf("%d",&op[i][0]);
	if(op[i][0]==1)scanf("%d",&op[i][1]),wu[op[i][1]]=1;
	}
	tubao();
	for(i=Q;i>=1;i--)
	{//dfs(rt);cout<<endl;
		if(op[i][0]==2)
		daan[i]=ans;
		else
		{
			int st=dui[op[i][1]];
           int ll=xiao(D[st].x),rr=da(x[ll]);
		    if(xl(x[ll],y[ll],D[st].x,D[st].y)>xl(x[ll],y[ll],x[rr],y[rr]))
            {
            	ans-=jl(x[ll],y[ll],x[rr],y[rr]);
            	lll=xiao(x[ll]);
        while(x[lll]<x[ll]&&xl(x[lll],y[lll],D[st].x,D[st].y)>xl(x[lll],y[lll],x[ll],y[ll]))
		{ ans-=jl(x[ll],y[ll],x[lll],y[lll]);   del(ll);ll=lll;lll=xiao(x[ll]);		}              
                  	rrr=da(x[rr]);
        while(x[rrr]>x[rr]&&xl(x[rr],y[rr],D[st].x,D[st].y)<xl(x[rrr],y[rrr],D[st].x,D[st].y))
		{ ans-=jl(x[rr],y[rr],x[rrr],y[rrr]);   del(rr);
		rr=rrr;
		rrr=da(x[rr]);		}              
            ans+=jl(x[ll],y[ll],D[st].x,D[st].y)+jl(x[rr],y[rr],D[st].x,D[st].y);		
		   splay(ll,0);
		   int p=ch[ll][1];
		   if(p==0)
		   {
		   	set(ll,1,xin(D[st].x,D[st].y));
		   }else
		   {
		   while(ch[p][0])p=ch[p][0];
		   set(p,0,xin(D[st].x,D[st].y));
	       }splay(tot,0);
			}
		}		
	}
for(i=1;i<=Q;i++)
if(op[i][0]==2)printf("%.2lf\n",daan[i]);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值