您的位置:首页 > 其它

Bzoj3533:[Sdoi2014]向量集:线段树+凸包+三分

2016-06-23 19:21 501 查看
题目链接[Sdoi2014]向量集

维护一颗线段树,线段树每个节点上有对应区间的上下凸壳

可以发现答案一定在凸壳上取得,所以在凸壳上三分即可,y>=0时在上凸壳上三分,否则在下凸壳

#include<vector>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define ll long long
#define pb push_back
#define pii pair<ll,ll>
#define mp make_pair
#define dc(x) ((x)^(ans&0x7fffffff))
using namespace std;
const int maxn=400010;
const ll inf=1e17;
struct seg{
int l,r,mr;
vector< pii >vu;
vector< pii >vd;
seg *lc,*rc;
};
seg *root=new seg();
int n,sta[maxn],opt,cnt=0,l[maxn],r[maxn];
ll X[maxn],Y[maxn],ans=0;
char c,s[maxn];
struct point{ll x,y;}po[maxn],tmpp[maxn];

ll cross(ll a,ll b,ll c,ll d,ll e,ll f){
ll x1=c-a,y1=d-b;
ll x2=e-a,y2=f-b;
return 1ll*x1*y2-1ll*x2*y1;
}

void build(seg *p,int l,int r){
p->l=l; p->r=r;
if (l+1==r){
p->lc=p->rc=NULL; return;
}else if (l+1<r){
int mid=(l+r)>>1;
p->lc=new seg();
p->rc=new seg();
if (l<mid) build(p->lc,l,mid);
if (mid<r) build(p->rc,mid,r);
}
}

bool cmp(const point &a,const point &b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}

void make_convex(seg *p,int l,int r){
if (r-l+1<=5){
for (int i=l;i<=r;++i) p->vu.pb(mp(po[i].x,po[i].y));
for (int i=l;i<=r;++i) p->vd.pb(mp(po[i].x,po[i].y));
}else{
for (int i=l;i<=r;++i) tmpp[i]=po[i];
sort(po+l,po+r+1,cmp);
int top=0;
sta[++top]=l; sta[++top]=l+1;
for (int i=l+2;i<=r;++i){
while (top>1&&cross(po[sta[top-1]].x,po[sta[top-1]].y,po[sta[top]].x,po[sta[top]].y,po[i].x,po[i].y)>0) top--;
sta[++top]=i;
}
for (int i=1;i<=top;++i) p->vu.pb(mp(po[sta[i]].x,po[sta[i]].y));
top=0; sta[++top]=r; sta[++top]=r-1;
for (int i=r-2;i>=l;--i){
while (top>1&&cross(po[sta[top-1]].x,po[sta[top-1]].y,po[sta[top]].x,po[sta[top]].y,po[i].x,po[i].y)>0) top--;
sta[++top]=i;
}
for (int i=1;i<=top;++i) p->vd.pb(mp(po[sta[i]].x,po[sta[i]].y));
for (int i=l;i<=r;++i) po[i]=tmpp[i];
}
}

void add(seg *p,int l,int r){
if (l<=p->l&&p->r<=r){
p->mr=r; make_convex(p,l,r-1); return;
}else{
int mid=(p->l+p->r)>>1;
if (l<mid) add(p->lc,l,r);
if (mid<r) add(p->rc,l,r);
p->mr=p->rc->mr;
if (p->mr==p->r) make_convex(p,p->l,p->r-1);
}
}

ll getval(pii p,ll x,ll y){
return 1ll*p.first*x+1ll*p.second*y;
}

void worku(seg *p,ll x,ll y){
if (p->r-p->l<=5){
for (int i=0;i<p->vu.size();++i) ans=max(ans,getval(p->vu[i],x,y));
}
int l=0,r=p->vu.size()-1;
while (r-l>=3){
int ml=(l+l+r)/3,mr=(l+r+r)/3;
if (getval(p->vu[ml],x,y)<=getval(p->vu[mr],x,y)) l=ml;
else r=mr;
}
for (int i=l;i<=r;++i) ans=max(ans,getval(p->vu[i],x,y));
}

void workd(seg *p,ll x,ll y){
if (p->r-p->l<=5){
for (int i=0;i<p->vd.size();++i) ans=max(ans,getval(p->vd[i],x,y));
}
int l=0,r=p->vd.size()-1;
while (r-l>=3){
int ml=(l+l+r)/3,mr=(l+r+r)/3;
if (getval(p->vd[ml],x,y)<=getval(p->vd[mr],x,y)) l=ml;
else r=mr;
}
for (int i=l;i<=r;++i) ans=max(ans,getval(p->vd[i],x,y));
}

void ask(seg *p,int l,int r,ll x,ll y){
if (l<=p->l&&p->r<=r){
if (y>=0) worku(p,x,y);
else workd(p,x,y);
return;
}
int mid=(p->l+p->r)>>1;
if (l<mid) ask(p->lc,l,r,x,y);
if (mid<r) ask(p->rc,l,r,x,y);
}

int main(){
scanf("%d",&n); cin>>c;
if (c=='E') opt=0; else opt=1;
for (int i=1;i<=n;++i){
cin>>s[i];
if (s[i]=='A'){
++cnt; scanf("%lld%lld",&po[cnt].x,&po[cnt].y);
}else if (s[i]=='Q'){
scanf("%lld%lld%d%d",&X[i],&Y[i],&l[i],&r[i]);
}
}
build(root,1,cnt+1);
int now=1;
for (int i=1;i<=n;++i){
if (s[i]=='A'){
if (opt) po[now].x=dc(po[now].x),po[now].y=dc(po[now].y);
add(root,now,now+1); now++;
}else if (s[i]=='Q'){
if (opt) X[i]=dc(X[i]),Y[i]=dc(Y[i]),l[i]=dc(l[i]),r[i]=dc(r[i]);
ans=-inf;
ask(root,l[i],r[i]+1,X[i],Y[i]);
printf("%lld\n",ans);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息