【BZOJ3533】向量集(SDOI2014)-线段树+凸壳+二分
测试地址:向量集
做法:本题需要用到线段树+凸包+二分。
首先恭喜一下自己达成BZOJ200AC……(突然想起,这不会有多少人看得见)
令询问的向量为,序列中第个向量为,那么要求时,的最大值,令这个式子为,则有:
注意到时只需要算的最大值就行了,所以我们不考虑没有意义的问题。
当时,这相当于在所有点上作斜率为的直线,求最大的截距,显然可以维护一个上凸壳,然后在上凸壳上二分解决。
当时,直接将所有变成它们的相反数,这样就又转化为了求最大截距的问题,用上面的方法做就行了。
然而这只是一次询问的情况,要支持多次区间询问,我们就要用线段树维护一个区间内点的上凸壳。那插入操作怎么办?我们可以一开始先开好线段树的空间,但是只有当一个区间内的点被插入完整时,才计算这个区间的凸壳。显然可知,处理凸壳的总时间是,一次询问的时间是,可以通过此题。
以下是本人代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=400010;
const ll inf=1000000000ll*1000000000ll;
int n,tot=0,pos[N];
char s,op[3];
struct point
{
ll x,y;
point operator + (point a) const
{
point s={x+a.x,y+a.y};
return s;
}
point operator - (point a) const
{
point s={x-a.x,y-a.y};
return s;
}
ll operator * (point a) const
{
return x*a.y-y*a.x;
}
};
ll dot(point a,point b)
{
return a.x*b.x+a.y*b.y;
}
struct convex
{
int n;
point *a;
void init(int now)
{
n=0;
a=new point [now+5];
}
void push(point s)
{
while(n>1&&(s-a[n])*(a[n]-a[n-1])<=0) n--;
a[++n]=s;
}
void merge(convex &lc,convex &rc)
{
init(lc.n+rc.n);
int l=1,r=1;
while(l<=lc.n&&r<=rc.n)
{
int lx=lc.a[l].x,rx=rc.a[r].x;
if (lx<rx||(lx==rx&&lc.a[l].y<rc.a[r].y)) push(lc.a[l]),l++;
else push(rc.a[r]),r++;
}
if (l>lc.n)
{
while(r<=rc.n)
push(rc.a[r]),r++;
}
else
{
while(l<=lc.n)
push(lc.a[l]),l++;
}
}
ll find(ll x,ll y)
{
point s={x,y};
if (y<0) s.x=-x,s.y=-y;
int l=1,r=n;
while(l<r)
{
int mid=(l+r)>>1;
if (dot(a[mid],s)<=dot(a[mid+1],s)) l=mid+1;
else r=mid;
}
return dot(s,a[l]);
}
};
struct Seg
{
convex a[2];
}seg[N<<2];
ll decode(ll x,ll lastans)
{
return x^(lastans&0x7fffffff);
}
void buildtree(int no,int l,int r)
{
if (l==r) {pos[l]=no;return;}
int mid=(l+r)>>1;
buildtree(no<<1,l,mid);
buildtree(no<<1|1,mid+1,r);
}
void add(int id,ll x,ll y)
{
int now=pos[id];
point nxt={x,y};
seg[now].a[0].init(1);seg[now].a[0].push(nxt);
nxt.x=-x,nxt.y=-y;
seg[now].a[1].init(1);seg[now].a[1].push(nxt);
while((now&1)&&now>1)
{
now>>=1;
seg[now].a[0].merge(seg[now<<1].a[0],seg[now<<1|1].a[0]);
seg[now].a[1].merge(seg[now<<1].a[1],seg[now<<1|1].a[1]);
}
}
ll query(int no,int l,int r,int s,int t,ll x,ll y)
{
if (l>=s&&r<=t) return seg[no].a[y<0].find(x,y);
ll ans=-inf;
int mid=(l+r)>>1;
if (s<=mid) ans=max(ans,query(no<<1,l,mid,s,t,x,y));
if (t>mid) ans=max(ans,query(no<<1|1,mid+1,r,s,t,x,y));
return ans;
}
int main()
{
scanf("%d %c",&n,&s);
ll lastans=0;
buildtree(1,1,n);
for(int i=1;i<=n;i++)
{
ll x,y;
int l,r;
scanf("%s",op);
if (op[0]=='A')
{
scanf("%lld%lld",&x,&y);
if (s!='E') x=decode(x,lastans),y=decode(y,lastans);
add(++tot,x,y);
}
else
{
scanf("%lld%lld%d%d",&x,&y,&l,&r);
if (s!='E')
{
x=decode(x,lastans),y=decode(y,lastans);
l=decode(l,lastans),r=decode(r,lastans);
}
printf("%lld\n",lastans=query(1,1,n,l,r,x,y));
}
}
return 0;
}