[BZOJ 4311] 向量

一、题目

点此看题

二、解法

线段树分治可以解决在线插入难,在线删除难,回退难的问题。

就好比我们只会凸包的离线插入,那么在线段树上的每一个节点上维护一个凸包,然后去更新它管辖区间的所有询问即可,每个询问只会被更新 (log) 次所以复杂度是对的。

忘了说这道题为什么要用凸包了,对于询问 ((x,y)) 考虑两个向量 ((x_1,y_1),(x_2,y_2)),设 (x_1<x_2),那么第二个向量比第一个向量更优的条件是:

[xx_1+yy_1<xx_2+yy_2 ]

[frac{-y_2+y_1}{x_2-x_1}<frac{x}{y} ]

这相当于维护一个 ((x_i,-y_i)) 的下凸包,然后找第一个斜率大于等于 (frac{x}{y}) 的线段即可。

实现细节:以总操作个数来建线段树,避免以询问个数来建线段树的细节,如果你调不出来就暴力访问凸包上的每个点,然后发现可以直接过掉。

#include <cstdio>
#include <vector>
#include <cassert>
#include <iostream>
#include <algorithm>
using namespace std;
const int M = 2000005;
#define db double
#define ll long long 
#define int long long
int read()
{
    int x=0,f=1;char c;
    while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    return x*f;
}
int n,m,k,tp,vx[M],vy[M],vl[M],vr[M],qx[M],qy[M],id[M];
vector<int> p[4*M];ll nx,ny,ans[M];int v[M];db kk[M];
void ins(int i,int l,int r,int L,int R,int x)
{
	if(L>r || l>R) return ;
	if(L<=l && r<=R)
	{
		p[i].push_back(x);
		return ;
	}
	int mid=(l+r)>>1;
	ins(i<<1,l,mid,L,R,x);
	ins(i<<1|1,mid+1,r,L,R,x);
}
int cmp(int x,int y)
{
	return vx[x]==vx[y]?vy[x]<vy[y]:vx[x]<vx[y];
}
db slope(int x,int y)
{
	return 1.0*(vy[x]-vy[y])/(vx[y]-vx[x]);
}
void work(int x)
{
	tp=0;
	sort(p[x].begin(),p[x].end(),cmp);
	for(int i=0,sz=p[x].size();i<sz;i++)
	{
		int t=p[x][i];
		while(tp>1 && slope(v[tp],t)
		<=slope(v[tp-1],v[tp])) tp--;
		v[++tp]=t;
	}
	v[tp+1]=0;
	for(int i=1;i<tp;i++)
		kk[i]=slope(v[i],v[i+1]);
}
ll dot(int x)
{
	return vx[x]*nx+vy[x]*ny;
}
void zxy(int x)
{
	nx=qx[x];ny=qy[x];
	int t=lower_bound(kk+1,kk+tp,1.0*nx/ny)-kk;
	//for(int i=1;i<=tp;i++)
	//	ans[x]=max(ans[x],dot(v[i]));
	if(t>tp) return ;
	ans[x]=max(ans[x],dot(v[t]));
	ans[x]=max(ans[x],dot(v[t-1]));
	ans[x]=max(ans[x],dot(v[t+1]));
	//return max(dot(v[t]),dot(v[t+1]));
}
void build(int i,int l,int r)
{
	work(i);
	for(int i=l;i<=r;i++)
		if(id[i]) zxy(id[i]);
	if(l==r) return ;
	int mid=(l+r)>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
}
signed main()
{
	//freopen("1.in","r",stdin);
	//freopen("zxy.out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++)
	{
		int t=read();
		if(t==1)
		{
			m++;vl[m]=i;
			vx[m]=read();vy[m]=read();
		}
		if(t==2)
			vr[read()]=i;
		if(t==3)
			qx[++k]=read(),qy[k]=read(),id[i]=k;
	}
	for(int i=1;i<=m;i++)
	{
		if(vr[i]==0) vr[i]=n;
		ins(1,1,n,vl[i],vr[i],i);
	}
	build(1,1,n);
	for(int i=1;i<=k;i++)
		printf("%lld
",ans[i]);
}
原文地址:https://www.cnblogs.com/C202044zxy/p/15187944.html