ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[BZOJ 4311] 向量

2021-08-26 09:34:30  阅读:205  来源: 互联网

标签:4311 int 线段 凸包 dot ans include 向量 BZOJ


一、题目

点此看题

二、解法

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

就好比我们只会凸包的离线插入,那么在线段树上的每一个节点上维护一个凸包,然后去更新它管辖区间的所有询问即可,每个询问只会被更新 \(\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\n",ans[i]);
}

标签:4311,int,线段,凸包,dot,ans,include,向量,BZOJ
来源: https://www.cnblogs.com/C202044zxy/p/15187944.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有