博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【线段树分治】[BZOJ4311]向量
阅读量:5291 次
发布时间:2019-06-14

本文共 3124 字,大约阅读时间需要 10 分钟。

描述

Description

你要维护一个向量集合,支持以下操作:
1.插入一个向量(x,y)
2.删除插入的第i个向量
3.查询当前集合与(x,y)点积的最大值是多少。如果当前是空集输出0

Input

第一行输入一个整数n,表示操作个数
接下来n行,每行先是一个整数t表示类型,如果t=1,输入向量
(x,y);如果t=2,输入id表示删除第id个向量;否则输入(x,y),查询
与向量(x,y)点积最大值是多少。
保证一个向量只会被删除一次,不会删没有插入过的向量

Output

对于每条t=3的询问,输出一个答案

Sample Input

5

1 3 3
1 1 4
3 3 3
2 1
3 3 3

Sample Output

18
15

HINT

n<=200000 1<=x,y<=10^6

Source

NOI2015模拟题by 杨定澄

分析

所有向量都在第一象限,根据点积的定义,我们作询问向量OQ的垂线,从无穷远处向原点扫描过来,碰到的集合中的第一个点对应的向量和OQ的点积一定是最大的。

这里写图片描述
可以发现,这样的点一定在原集合点集的上凸包上,我们只要建出凸包,在凸包上二分(或三分)就可以找到那个点。。
如果没有删除操作,我们可以用CDQ分治来做这道题。
但是有了删除操作,一个向量只能在一段询问区间内生效,我们可以用线段树分治来做。
我们对询问建立线段树,然后把每一个向量插入到对应的询问区间,然后对每个节点建立凸包。
每次询问,对对应节点到根路径上的所有节点都进行一次查询即可得到答案。时间复杂度O(nlog2n)
我们可以将向量排序后插入,在求凸包的时候就不用再排序了。把所有询问按照极角排序后,发现决策点单调,那极角排序后再将询问插入线段树即可。我们遍历一遍线段树,同时进行归并排序,然后处理这个节点的向量对这个节点包含的询问的贡献,可以节省一些空间。时间复杂度O(nlogn)

代码 ==
#include
#include
#include
#define MAXN 200000using namespace std;void Read(int &x){ static char c; while(c=getchar(),c!=EOF) if(c>='0'&&c<='9'){ x=c-'0'; while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0'; ungetc(c,stdin); return; }}int n,ocnt,qcnt,bk,tmp[MAXN+10],tmp2[MAXN+10];long long ans[MAXN+10];struct point{ int x,y; inline point(){ } inline point(int x,int y):x(x),y(y){ } inline point operator-(const point &b)const{ return point(x-b.x,y-b.y); } bool operator<(const point &b)const{ if(x==b.x) return y
op;}tree[MAXN*4+10];void insert(int i,int l,int r,int ll,int rr,point *a){ if(ll<=l&&r<=rr){ tree[i].op.push_back(a); return; } if(ll>r||rr
>1); insert(i<<1,l,mid,ll,rr,a); insert((i<<1)|1,mid+1,r,ll,rr,a);}void read(){ Read(n); int i,p,x,y; for(i=1;i<=n;i++){ Read(p),Read(x); if(p==1){ Read(y); cg[++ocnt].x=point(x,y); cg[ocnt].l=qcnt+1; cg[ocnt].r=-1; } else if(p==2) cg[x].r=qcnt; else{ Read(y); Q[++qcnt]=point(x,y); } } sort(cg+1,cg+ocnt+1); for(i=1;i<=ocnt;i++){ if(cg[i].r==-1) cg[i].r=qcnt; if(cg[i].l>cg[i].r) continue; insert(1,1,qcnt,cg[i].l,cg[i].r,&cg[i].x); }}void Divide_Conqure(int i,int l,int r){ if(l==r){ tmp[l]=l; for(vector
::iterator j=tree[i].op.begin();j
>1),x,j,k; Divide_Conqure(i<<1,l,mid); Divide_Conqure((i<<1)|1,mid+1,r); x=l,j=mid+1,k=l; while(x<=mid||j<=r){ if(j>r||(x<=mid&&cross(Q[tmp[x]],Q[tmp[j]])<=0)) tmp2[k++]=tmp[x++]; else tmp2[k++]=tmp[j++]; } bk=0; for(x=l;x<=r;x++) tmp[x]=tmp2[x]; for(vector
::iterator v=tree[i].op.begin();v
1&&cross(*q[bk]-*q[bk-1],**v-*q[bk-1])>=0) bk--; q[++bk]=*v; } if(bk){ for(x=l,j=1;x<=r;x++){ while(j
dot(Q[tmp[x]],*q[j])) j++; ans[tmp[x]]=max(ans[tmp[x]],dot(Q[tmp[x]],*q[j])); } }}void print(){ int i; for(i=1;i<=qcnt;i++) printf("%lld\n",ans[i]);}int main(){ read(); Divide_Conqure(1,1,qcnt); print();}

转载于:https://www.cnblogs.com/outerform/p/5921800.html

你可能感兴趣的文章
C# 修饰符
查看>>
JavaScript启示录
查看>>
我需要什么样的浏览器?
查看>>
取textaera里的值
查看>>
java设计模式1--工厂方法模式(Factory Method)
查看>>
博客第一弹—聊聊HTML的那些事
查看>>
上海2017QCon个人分享总结
查看>>
HIVE快速入门 分类: B4_HIVE 2015-...
查看>>
Mysql安装方法及安装问题解决
查看>>
Java动态代理的两种实现方式:
查看>>
PHP trait
查看>>
Redis的常用命令(三)
查看>>
HDOJ 4749 Parade Show
查看>>
python 多线程并发threading & 任务队列Queue
查看>>
【黑马程序员】资深程序员的见解
查看>>
1_fbauto
查看>>
IO体系、集合体系、多线程、jdbc
查看>>
Spring Cloud Turbine微服务集群实时监控
查看>>
django过滤富文本XSS
查看>>
Java异常处理机制及两种异常的区别
查看>>