• bzoj 3533 [Sdoi2014]向量集 线段树+凸包+三分(+动态开数组) 好题


    题目大意

    维护一个向量集合,在线支持以下操作:
    "A x y (|x|,|y| < =10^8)":加入向量(x,y);
    "Q x y l r (|x|,|y| < =10^8,1 < =L < =R < =T,其中T为已经加入的向量个数)询问第L个到第R个加入的向量与向量(x,y)的点积的最大值。
    集合初始时为空。

    分析

    题目中相当于给出一堆点((z,w))
    询问点(x,y)
    (maximize(ans=xz+yw))
    (frac {ans} y=frac x y z+w)
    (w=-frac x y z+frac {ans} y)
    相当于函数(w=f(z)=-frac x y z+frac {ans} y)
    就是一条斜率为(-frac x y),截距为(frac {ans} y)的线
    对于一次询问中,斜率不变,截距记为(D)
    ①y>0,我们要使ans尽可能大,则截距尽可能大,答案在上凸壳
    ②y<0,我们要使ans尽可能大,则截距尽可能小,答案在下凸壳
    ③y=0,我们要使ans尽可能大,则xz尽可能大,z只会在最左最右,而最左最右的点一定在凸壳上,所以在上下凸壳找都行

    做法

    线段树维护凸包+三分
    当然不能每插入一个点都合并一下
    注意到一个没有插满的线段是不会被询问的
    所以只有当插入位置为线段右端点时,将线段上的点搞一个凸包
    每条线段合并一次,每条线段上有恰好(r-l+1)个点
    所以每层n个点,凸包(nlog n),总共(log n)
    总复杂度(n log^2 n)

    注意

    1.三分时要保证函数中没有重点,不然会有(bug)
    2.(ans)可能为负,所以取(max)时的初始值为(-INF)
    3.线段树大小为比(n*2)大的一个二进制数
    4.数组大小为(n*(log n +1)+1)

    小结

    扫描线的思维是找单调性,判断答案是否在凸包上的一种好方法
    这种题只是说答案在凸包上,实际和凸包没有太大的关联
    所以我们不必要先搞出询问区间的凸包再三分
    只需要分段取出答案再取max就好了

    solution

    #include <cstdio>
    #include <cstdlib>
    #include <cctype>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    typedef long long LL;
    using namespace std;
    const int M=1048576;
    const int N=10485763;
    const LL INF=9223372036854775807;
    
    LL rd(){
    	LL x=0;bool f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    	for(;isdigit(c);c=getchar()) x=x*10+c-48;
    	return f?x:-x;
    }
    
    struct pt{
    	LL x,y;
    	pt (LL _x=0.0,LL _y=0.0){x=_x;y=_y;}
    };
    bool operator <(pt x,pt y){return (x.x!=y.x)?(x.x<y.x):(x.y<y.y);}
    pt operator +(pt x,pt y){return pt(x.x+y.x,x.y+y.y);}
    pt operator -(pt x,pt y){return pt(x.x-y.x,x.y-y.y);}
    LL dot(pt x,pt y){return x.x*y.x+x.y*y.y;}
    LL det(pt x,pt y){return x.x*y.y-x.y*y.x;}
    LL side(pt x,pt y,pt z){return det(y-x,z-x);}
    
    LL n,lst,typ,ps;
    char s[7];
    int g[M<<1],te;
    struct edge{pt y;int nxt;}e[N];
    
    void addedge(int x,pt y){
    	e[++te].y=y;e[te].nxt=g[x];g[x]=te;
    }
    
    pt mempool[N];
    int tot;
    struct arr{
    	pt *s;int top;
    	void rsz(int n){
    		top=0;
    		s=mempool+tot+1;
    		tot+=n+1;
    	}
    }up[M<<1],dw[M<<1];
    pt a[M];
    
    LL decode(LL x){
    	if(typ) return x^(lst&0x7fffffff);
    	return x;
    }
    
    void convex(int x){
    	int p,tp=0,i;
    	for(p=g[x];p;p=e[p].nxt) a[++tp]=e[p].y;
    	sort(a+1,a+tp+1);
    	up[x].rsz(tp);
    	for(i=1;i<=tp;i++){
    		while(up[x].top>1&&side(up[x].s[up[x].top-1],up[x].s[up[x].top],a[i])>=0) up[x].top--;
    		up[x].s[++up[x].top]=a[i];
    	}
    	dw[x].rsz(tp);
    	for(i=1;i<=tp;i++){
    		while(dw[x].top>1&&side(dw[x].s[dw[x].top-1],dw[x].s[dw[x].top],a[i])<=0) dw[x].top--;
    		dw[x].s[++dw[x].top]=a[i];
    	}
    }
    
    LL gmx(int x,pt d){
    	arr &nw=(d.y>0)?up[x]:dw[x];
    	int l=1,r=nw.top,m1,m2,i;
    	LL tp1,tp2;
    	while(r-l>=3){
    		m1=(l+l+r)/3;
    		m2=(r+l+r)/3;
    		tp1=dot(nw.s[m1],d);
    		tp2=dot(nw.s[m2],d);
    		if(tp1<tp2) l=m1;
    		else r=m2;
    	}
    	LL ans=-INF;
    	for(i=l;i<=r;i++) ans=max(ans,dot(nw.s[i],d));
    	return ans;
    }
    
    void ins(int x,int l,int r,int to,pt d){
    	if(l==r){
    		up[x].rsz(1);dw[x].rsz(1);
    		up[x].top=dw[x].top=1;
    		up[x].s[1]=dw[x].s[1]=d;
    		return;
    	}
    	int mid=l+r>>1;
    	if(to<=mid) ins(x<<1,l,mid,to,d);
    	else ins(x<<1|1,mid+1,r,to,d);
    	addedge(x,d);
    	if(r==to) convex(x);
    }
    
    LL get(int x,int l,int r,int tl,int tr,pt d){
    	if(tl<=l&&r<=tr) return gmx(x,d);
    	int mid=l+r>>1;
    	LL res=-INF;
    	if(tl<=mid) res=max(res,get(x<<1,l,mid,tl,tr,d));
    	if(mid<tr) res=max(res,get(x<<1|1,mid+1,r,tl,tr,d));
    	return res;
    }
    
    int main(){
    
    	n=rd();scanf("%s",s);
    	if(s[0]!='E') typ=1; else typ=0;
    	
    	int i;
    	LL x,y,L,R;
    	for(i=1;i<=n;i++){
    		scanf("%s",s);
    		if(s[0]=='A'){
    			++ps;
    			x=decode(rd());
    			y=decode(rd());
    			pt p=pt(x,y);
    			ins(1,1,n,ps,p);
    		}
    		else{
    			x=decode(rd());
    			y=decode(rd());
    			L=decode(rd());
    			R=decode(rd());
    			pt p=pt(x,y);
    			lst=get(1,1,n,L,R,p);
    			printf("%lld
    ",lst);
    		}
    	}	
    	return 0;
    }
    
  • 相关阅读:
    appium+python界面滑动
    selenium+python元素定位总结
    PAT甲级1017. Queueing at Bank
    PAT甲级1016. Phone Bills
    PAT甲级1014. Waiting in Line
    PAT甲级1013. Battle Over Cities
    PAT甲级1012. The Best Rank
    PAT甲级1010. Radix
    PAT甲级1003. Emergency
    hihocoder1320 160周 压缩字符串
  • 原文地址:https://www.cnblogs.com/acha/p/6477791.html
Copyright © 2020-2023  润新知