BZOJ 3533 Sdoi2014 向量集 线段树+凸包+三分

题目大意:给定一个平面,维护下列操作:

1.插入一个向量

2.询问第l到r个插入的向量中与某个向量叉积的最大值

强制在线

首先答案一定在凸包上 而且如果y>0则在上凸包上 否则就在下凸包上

且答案在同一凸包上呈现单峰函数 满足三分性质

但是现在让我们维护某个区间内的凸包,因此我们可以使用线段树

由于凸包的合并是线性的,我们不能每插入一个点都路径维护一下

这个很好办嘛!反正包含未插入点的线段树节点一定不会被查询到,因此只有在当前插入的点是线段树节点的右端点时才合并凸包不就好了嘛!

然后查询时在对应凸包上三分即可

注意两个节点y值相等的情况。。。再也不敢乱写凸包了。。。

#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 400400
using namespace std;
struct Point{
	long long x,y;
	Point() {}
	Point(long long _,long long __):
		x(_),y(__) {}
	friend Point operator + (const Point &p1,const Point &p2)
	{
		return Point(p1.x+p2.x,p1.y+p2.y);
	}
	friend Point operator - (const Point &p1,const Point &p2)
	{
		return Point(p1.x-p2.x,p1.y-p2.y);
	}
	friend long long operator * (const Point &p1,const Point &p2)
	{
		return p1.x*p2.y-p1.y*p2.x;
	}
	friend long long operator ^ (const Point &p1,const Point &p2)
	{
		return p1.x*p2.x+p1.y*p2.y;
	}
	friend bool operator < (const Point &p1,const Point &p2)
	{
		return p1.x<p2.x || p1.x==p2.x&&p1.y<p2.y;
	}
};
int n,tot;
char type[10];
long long last_ans;
void Cover_Merge(const vector<Point> &h1,const vector<Point> &h2,vector<Point> &h)
{
	vector<Point>::const_iterator i=h1.begin(),j=h2.begin();
	int top=0;
	while( i!=h1.end() || j!=h2.end() )
	{
		Point p=i==h1.end()?*j++:j==h2.end()?*i++:(*i<*j?*i++:*j++);
		while( top>=2 && (h[top-1]-h[top-2])*(p-h[top-1])>=0 )
			h.pop_back(),top--;
		h.push_back(p),top++;
	}
}
void Below_Merge(const vector<Point> &h1,const vector<Point> &h2,vector<Point> &h)
{
	vector<Point>::const_iterator i=h1.begin(),j=h2.begin();
	int top=0;
	while( i!=h1.end() || j!=h2.end() )
	{
		Point p=i==h1.end()?*j++:j==h2.end()?*i++:(*i<*j?*i++:*j++);
		while( top>=2 && (h[top-1]-h[top-2])*(p-h[top-1])<=0 )
			h.pop_back(),top--;
		h.push_back(p),top++;
	}
}
long long Trisection(const vector<Point> &h,const Point &p)
{
	int i,l=0,r=h.size()-1;
	while(r-l>2)
	{
		int lmid=(l+l+r)/3,rmid=(l+r+r)/3;
		if( (h[lmid]^p)>(h[rmid]^p) )
			r=rmid;
		else
			l=lmid;
	}
	long long re=0xefefefefefefefefll;
	for(i=l;i<=r;i++)
		re=max(re,h[i]^p);
	return re;
}
struct Segtree{
	Segtree *ls,*rs;
	vector<Point> cover,below;
	void* operator new (size_t)
	{
		static Segtree *mempool,*C;
		if(C==mempool)
			mempool=(C=new Segtree[1<<16])+(1<<16);
		C->ls=0x0;
		C->rs=0x0;
		return C++;
	}
	friend void Insert(Segtree *&p,int x,int y,int pos,const Point &point)
	{
		int mid=x+y>>1;
		if(!p) p=new Segtree;
		if(x==y)
		{
			p->cover.push_back(point);
			p->below.push_back(point);
			return ;
		}
		if(pos<=mid)
			Insert(p->ls,x,mid,pos,point);
		else
			Insert(p->rs,mid+1,y,pos,point);
		if(pos==y)
		{
			Cover_Merge(p->ls->cover,p->rs->cover,p->cover);
			Below_Merge(p->ls->below,p->rs->below,p->below);
		}
	}
	long long Get_Ans(int x,int y,int l,int r,const Point &point)
	{
		int mid=x+y>>1;
		if(x==l&&y==r)
			return point.y>0?Trisection(cover,point):Trisection(below,point);
		if(r<=mid)
			return ls->Get_Ans(x,mid,l,r,point);
		if(l>mid)
			return rs->Get_Ans(mid+1,y,l,r,point);
		return max( ls->Get_Ans(x,mid,l,mid,point) , rs->Get_Ans(mid+1,y,mid+1,r,point) );
	}
}*tree=new Segtree;
#define Decode(x) ((x)^(last_ans&0x7fffffff))
int main()
{
	int i,x,y,l,r;
	char o[10];
	scanf("%d%s",&n,type);
	for(i=1;i<=n;i++)
	{
		scanf("%s",o);
		if(o[0]=='A')
		{
			scanf("%d%d",&x,&y);
			if(type[0]!='E')
				x=Decode(x),y=Decode(y);
			Point p(x,y);
			Insert(tree,1,n,++tot,p);
		}
		else
		{
			scanf("%d%d%d%d",&x,&y,&l,&r);
			if(type[0]!='E')
			{
				x=Decode(x);
				y=Decode(y);
				l=Decode(l);
				r=Decode(r);
			}
			Point p(x,y);
			#ifdef ONLINE_JUDGE
				printf("%lld\n",last_ans=tree->Get_Ans(1,n,l,r,p));
			#else
				printf("%I64d\n",last_ans=tree->Get_Ans(1,n,l,r,p));
			#endif
		}
	}
	return 0;
}


你可能感兴趣的:(线段树,凸包,三分,bzoj,BZOJ3533)