bzoj 3533 [Sdoi2014]向量集 线段树+凸包+三分(+动态开数组) 好题
题目大意
维护一个向量集合,在线支持以下操作:
"A x y (|x|,|y| < =10^8)":加入向量(x,y);
"Q x y l r (|x|,|y| < =10^8,1 < =L < =R < =T,其中T为已经加入的向量个数)询问第L个到第R个加入的向量与向量(x,y)的点积的最大值。
集合初始时为空。
分析
题目中相当于给出一堆点\((z,w)\)
询问点\(x,y\)
求\(maximize(ans=xz+yw)\)
\(\frac {ans} y=\frac x y z+w\)
\(w=-\frac x y z+\frac {ans} y\)
相当于函数\(w=f(z)=-\frac x y z+\frac {ans} y\)
就是一条斜率为\(-\frac x y\),截距为\(\frac {ans} y\)的线
对于一次询问中,斜率不变,截距记为\(D\)
①y>0,我们要使ans尽可能大,则截距尽可能大,答案在上凸壳
②y<0,我们要使ans尽可能大,则截距尽可能小,答案在下凸壳
③y=0,我们要使ans尽可能大,则xz尽可能大,z只会在最左最右,而最左最右的点一定在凸壳上,所以在上下凸壳找都行
做法
线段树维护凸包+三分
当然不能每插入一个点都合并一下
注意到一个没有插满的线段是不会被询问的
所以只有当插入位置为线段右端点时,将线段上的点搞一个凸包
每条线段合并一次,每条线段上有恰好\(r-l+1\)个点
所以每层n个点,凸包\(n\log n\),总共\(\log n\)层
总复杂度\(n \log^2 n\)
注意
1.三分时要保证函数中没有重点,不然会有\(bug\)
2.\(ans\)可能为负,所以取\(max\)时的初始值为\(-INF\)
3.线段树大小为比\(n*2\)大的一个二进制数
4.数组大小为\(n*(\log n +1)+1\)
小结
扫描线的思维是找单调性,判断答案是否在凸包上的一种好方法
这种题只是说答案在凸包上,实际和凸包没有太大的关联
所以我们不必要先搞出询问区间的凸包再三分
只需要分段取出答案再取max就好了
solution
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cmath>
#include <algorithm>
typedef long long LL;
using namespace std;
const int M=1048576;
const int N=10485763;
const LL INF=9223372036854775807;
LL rd(){
	LL x=0;bool f=1;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
	for(;isdigit(c);c=getchar()) x=x*10+c-48;
	return f?x:-x;
}
struct pt{
	LL x,y;
	pt (LL _x=0.0,LL _y=0.0){x=_x;y=_y;}
};
bool operator <(pt x,pt y){return (x.x!=y.x)?(x.x<y.x):(x.y<y.y);}
pt operator +(pt x,pt y){return pt(x.x+y.x,x.y+y.y);}
pt operator -(pt x,pt y){return pt(x.x-y.x,x.y-y.y);}
LL dot(pt x,pt y){return x.x*y.x+x.y*y.y;}
LL det(pt x,pt y){return x.x*y.y-x.y*y.x;}
LL side(pt x,pt y,pt z){return det(y-x,z-x);}
LL n,lst,typ,ps;
char s[7];
int g[M<<1],te;
struct edge{pt y;int nxt;}e[N];
void addedge(int x,pt y){
	e[++te].y=y;e[te].nxt=g[x];g[x]=te;
}
pt mempool[N];
int tot;
struct arr{
	pt *s;int top;
	void rsz(int n){
		top=0;
		s=mempool+tot+1;
		tot+=n+1;
	}
}up[M<<1],dw[M<<1];
pt a[M];
LL decode(LL x){
	if(typ) return x^(lst&0x7fffffff);
	return x;
}
void convex(int x){
	int p,tp=0,i;
	for(p=g[x];p;p=e[p].nxt) a[++tp]=e[p].y;
	sort(a+1,a+tp+1);
	up[x].rsz(tp);
	for(i=1;i<=tp;i++){
		while(up[x].top>1&&side(up[x].s[up[x].top-1],up[x].s[up[x].top],a[i])>=0) up[x].top--;
		up[x].s[++up[x].top]=a[i];
	}
	dw[x].rsz(tp);
	for(i=1;i<=tp;i++){
		while(dw[x].top>1&&side(dw[x].s[dw[x].top-1],dw[x].s[dw[x].top],a[i])<=0) dw[x].top--;
		dw[x].s[++dw[x].top]=a[i];
	}
}
LL gmx(int x,pt d){
	arr &nw=(d.y>0)?up[x]:dw[x];
	int l=1,r=nw.top,m1,m2,i;
	LL tp1,tp2;
	while(r-l>=3){
		m1=(l+l+r)/3;
		m2=(r+l+r)/3;
		tp1=dot(nw.s[m1],d);
		tp2=dot(nw.s[m2],d);
		if(tp1<tp2) l=m1;
		else r=m2;
	}
	LL ans=-INF;
	for(i=l;i<=r;i++) ans=max(ans,dot(nw.s[i],d));
	return ans;
}
void ins(int x,int l,int r,int to,pt d){
	if(l==r){
		up[x].rsz(1);dw[x].rsz(1);
		up[x].top=dw[x].top=1;
		up[x].s[1]=dw[x].s[1]=d;
		return;
	}
	int mid=l+r>>1;
	if(to<=mid) ins(x<<1,l,mid,to,d);
	else ins(x<<1|1,mid+1,r,to,d);
	addedge(x,d);
	if(r==to) convex(x);
}
LL get(int x,int l,int r,int tl,int tr,pt d){
	if(tl<=l&&r<=tr) return gmx(x,d);
	int mid=l+r>>1;
	LL res=-INF;
	if(tl<=mid) res=max(res,get(x<<1,l,mid,tl,tr,d));
	if(mid<tr) res=max(res,get(x<<1|1,mid+1,r,tl,tr,d));
	return res;
}
int main(){
	n=rd();scanf("%s",s);
	if(s[0]!='E') typ=1; else typ=0;
	int i;
	LL x,y,L,R;
	for(i=1;i<=n;i++){
		scanf("%s",s);
		if(s[0]=='A'){
			++ps;
			x=decode(rd());
			y=decode(rd());
			pt p=pt(x,y);
			ins(1,1,n,ps,p);
		}
		else{
			x=decode(rd());
			y=decode(rd());
			L=decode(rd());
			R=decode(rd());
			pt p=pt(x,y);
			lst=get(1,1,n,L,R,p);
			printf("%lld\n",lst);
		}
	}
	return 0;
}
												
											bzoj 3533 [Sdoi2014]向量集 线段树+凸包+三分(+动态开数组) 好题的更多相关文章
- BZOJ 3533: [Sdoi2014]向量集( 线段树 + 三分 )
		
答案一定是在凸壳上的(y>0上凸壳, y<0下凸壳). 线段树维护, 至多N次询问, 每次询问影响O(logN)数量级的线段树结点, 每个结点O(logN)暴力建凸壳, 然后O(logN) ...
 - bzoj 3533: [Sdoi2014]向量集  线段树维护凸包
		
题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=3533 题解: 首先我们把这些向量都平移到原点.这样我们就发现: 对于每次询问所得到的an ...
 - [SDOI2014][BZOJ3533] 向量集 [线段树+凸包]
		
题面 BZOJ传送门 思路 首先当然是推式子 对于一个询问点$(x_0,y_0$和给定向量$(x_1,y_1)$来说,点积这么表达: $A=x_0x_1+y_0y_1$ 首先肯定是考虑大小关系:$x_ ...
 - BZOJ3533:[SDOI2014]向量集(线段树,三分,凸包)
		
Description 维护一个向量集合,在线支持以下操作: "A x y (|x|,|y| < =10^8)":加入向量(x,y); " Q x y l r (| ...
 - 【bzoj3533】[Sdoi2014]向量集  线段树+STL-vector维护凸包
		
题目描述 维护一个向量集合,在线支持以下操作:"A x y (|x|,|y| < =10^8)":加入向量(x,y);"Q x y l r (|x|,|y| < ...
 - bzoj 4311 向量 时间线建线段树+凸包+三分
		
题目大意 你要维护一个向量集合,支持以下操作: 1.插入一个向量(x,y) 2.删除插入的第i个向量 3.查询当前集合与(x,y)点积的最大值是多少.如果当前是空集输出0 分析 按时间线建线段树 大致 ...
 - BZOJ 3910 并查集+线段树合并
		
思路: 1. 并查集+线段树合并 记得f[LCA]==LCA的时候 f[LCA]=fa[LCA] 2.LCT(并不会写啊...) //By SiriusRen #include <cstdio& ...
 - BZOJ3533 [Sdoi2014]向量集  【线段树 + 凸包 + 三分】
		
题目链接 BZOJ3533 题解 我们设询问的向量为\((x_0,y_0)\),参与乘积的向量为\((x,y)\) 则有 \[ \begin{aligned} ans &= x_0x + y_ ...
 - 【BZOJ】4311: 向量(线段树分治板子题)
		
题解 我们可以根据点积的定义,垂直于原点到给定点构成的直线作一条直线,从正无穷往下平移,第一个碰到的点就是答案 像什么,上凸壳哇 可是--动态维护上凸壳? 我们可以离线,计算每个点能造成贡献的一个询问 ...
 
随机推荐
- java8关于LocalDate,Date
			
关于java8中的新的时间日期类 public static void main(String[] args) { Date date = new Date(); LocalDate localDat ...
 - 01_9_Struts用ModelDriven接收参数
			
01_9_Struts用ModelDriven接收参数 1. 配置struts.xml文件 <package name="user" namespace="/use ...
 - CentOS 7.4 基于LNMP搭建wordpress
			
之前有好多次搭建wordpress的经历,有在Ubuntu系统上,有在CentOS7.2系统上,但都是搭完还是稀里糊涂的,因为好多都是教程上照着敲的.这次好好出个教程,以便以后方便查看. 准备工作:C ...
 - 使用Spring MVC后实现一个BaseController
			
使用Spring MVC技术后,可以实现一个基类的Controller类来分装一些MVC常用的方法,其他的Controller都继承自这个BaseController,这样在使用常用的方法时将会变得非 ...
 - 基于axios的vue插件,让http请求更简单
			
ajax-plus 基于axios 的 Vue 插件 如何使用 npm 模块引入 首先通过 npm 安装 ```npm install --save ajax-plus or yarn add aja ...
 - python面试题之什么是lambda函数?
			
lambda表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数. lambda所表示的匿名函数的内容应该是很简单的,如果复杂的话,干脆就重新定义一个函数了,使用l ...
 - poj 3614 伪素数问题
			
题意:1.p不是素数 2.(a^p)%p=a 输出yes 不满足输出no 思路: 判断素数问题,直接暴力判断 bool is_prime(int n) { for(int i=2;i*i<= ...
 - poj 1995 快速幂
			
题意:给出A1,…,AH,B1,…,BH以及M,求(A1^B1+A2^B2+ … +AH^BH)mod M. 思路:快速幂 实例 3^11 11=2^0+2^1+2^3 => 3^1*3 ...
 - SPOJ QTREE4 - Query on a tree IV 树分治
			
题意: 给出一棵边带权的树,初始树上所有节点都是白色. 有两种操作: C x,改变节点x的颜色,即白变黑,黑变白 A,询问树中最远的两个白色节点的距离,这两个白色节点可以重合(此时距离为0). 分析: ...
 - Python动态属性和特性(一)
			
在Python中,数据的属性和处理数据的方法统称为属性.其实,方式只是可调用的属性.除了这二者之外,我们还可以创建特性(property),在不改变类接口的前提下,使用存取方法(即读取值和设置值方法) ...