[LOJ2197][线段树][凸包][三分]SDOI2014:向量集

LOJ2197

和UOJ191unknown类似
我们知道点积等于一个向量的长度乘以另一个向量在这个向量上的投影的长度
那么如果我们把范围限制在180°内,则这个函数是单峰的,那就可以线段树维护上下凸壳,查找的时候三分
但是直接维护会T飞,因为需要合并,复杂度很高
换一种方法,我们是从左到右依次加入的,那就意味着如果我们要查询线段树的一个节点的话,那这个节点对应的区间一定被填满了,所以我们可以在填满节点的时候再合并,每个节点就只会被合并一次了
vector的常数巨大,不知道为什么,在网上看到一个用内存池的就照着写了一发,要快很多

Code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=1048576;
const ll INF=9223372036854775807;
struct point{
	int x,y;
	point(){}
	point(int _x,int _y):x(_x),y(_y){}
	friend inline point operator + (const point &a,const point &b){return point(a.x+b.x,a.y+b.y);}
	friend inline point operator - (const point &a,const point &b){return point(a.x-b.x,a.y-b.y);}
	friend inline ll operator * (const point &a,const point &b){return 1ll*a.x*b.y-1ll*a.y*b.x;}
	friend inline ll dot (const point &a,const point &b){return 1ll*a.x*b.x+1ll*a.y*b.y;}
	inline bool operator < (const point &rhs)const{return (x==rhs.x)?y<rhs.y:x<rhs.x;}
	inline ll dis(){return 1ll*x*x+1ll*y*y;}
};
inline ll decode(ll x,ll lastans){return x^(lastans&0x7fffffff);}

#define debug(kd,i) cerr<<kd[i].x<<" "<<kd[i].y<<endl;

const int M=10485763;

point vis[M];int head[N<<1],nxt[M],etot=0;
inline void add(int x,point y){vis[++etot]=y;nxt[etot]=head[x];head[x]=etot;}
point mempool[M];
int tot;
struct arr{
	point *s;int top;
	inline void rsz(int n){
		top=0;
		s=mempool+tot+1;
		tot+=n+1;
	}
}up[N<<1],dw[N<<1];
point a[N];
namespace segtree{
	struct seg{int l,r;}tr[N<<2];
	inline void graham(int k){
		int l=0,i;
   		for(int i=head[k];i;i=nxt[i]) a[++l]=vis[i];
   		sort(a+1,a+l+1);
		up[k].rsz(l);
		for(int i=1;i<=l;i++){
			while(up[k].top>1 && (up[k].s[up[k].top]-up[k].s[up[k].top-1])*(a[i]-up[k].s[up[k].top-1])>=0) --up[k].top;
			up[k].s[++up[k].top]=a[i];
		}
		dw[k].rsz(l);
		for(int i=1;i<=l;i++){
			while(dw[k].top>1 && (dw[k].s[dw[k].top]-dw[k].s[dw[k].top-1])*(a[i]-dw[k].s[dw[k].top-1])<=0) --dw[k].top;
			dw[k].s[++dw[k].top]=a[i];
		}
	}
	inline ll calc(int k,point v){
		arr &tmp=(v.y>0)?up[k]:dw[k];
		int l=1,r=tmp.top;
		while(r-l>=3){
			int m1=(l+l+r)/3,m2=(r+r+l)/3;
			if(dot(tmp.s[m1],v)<dot(tmp.s[m2],v)) l=m1;
			else r=m2;
		}
		ll ans=-INF;
		for(int i=l;i<=r;i++) ans=max(ans,dot(tmp.s[i],v));
		return ans;
	}
	void modify(int k,int l,int r,int pos,point v){
		if(l==r){
			up[k].rsz(1);dw[k].rsz(1);
			up[k].top=dw[k].top=1;
			up[k].s[1]=dw[k].s[1]=v;
			return;
		}
		int mid=l+r>>1;
		if(pos<=mid) modify(k<<1,l,mid,pos,v);
		else modify(k<<1|1,mid+1,r,pos,v);
		add(k,v);
		if(pos==r) graham(k);
	}
	ll query(int k,int l,int r,int ql,int qr,point v){
		if(ql<=l && r<=qr) return calc(k,v);
		int mid=l+r>>1;ll ans=-INF;
		if(ql<=mid) ans=max(ans,query(k<<1,l,mid,ql,qr,v));
		if(mid<qr) ans=max(ans,query(k<<1|1,mid+1,r,ql,qr,v));
		return ans;
	}
}
using namespace segtree;
char s[7];
ll ans=0;
int main(){
	int n=read(),m=0;scanf("%s",s+1);
	int t=s[1]=='E'?0:1;
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		if(s[1]=='A'){
			int x=read(),y=read();
			if(t) x=decode(x,ans),y=decode(y,ans);
			modify(1,1,n,++m,point(x,y));
		}
		else{
			int x=read(),y=read();
			if(t) x=decode(x,ans),y=decode(y,ans);
			int l=read(),r=read();
			if(t) l=decode(l,ans),r=decode(r,ans);
			ans=query(1,1,n,l,r,point(x,y));
			cout<<ans<<"\n";
		}
	}
	return 0;
}
©️2020 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值