[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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章