• P3122 [USACO15FEB]Fencing the Herd G


    https://www.luogu.com.cn/problem/P3122
    cdq 分治+凸包

    发现一个线是有用的等价于对于所有的 ((x_0,y_0)) 都有 (Ax_0+By_0<C) 或都有 (Ax_0+By_0>C)
    于是问题就转化为了对于每个直线求 (Ax_0+By_0) 的最大和最小值

    考虑把一开始的 (n) 个点也看成插入,问每条直线是否有用就是查询上面说的最大、最小值,于是 cdq 分治,在 ([l,r]) 区间里把左右子区间中,各自的插入对自己中的查询的影响递归处理,于是只用计算左区间中插入点对右区间中查询的影响
    不妨设 (B>0),先考虑如何找最大值,则有 (Ax+By=max Rightarrow y=-dfrac{A}{B}x+dfrac{max}{B}),于是只用最大化截距即可
    由于斜率固定,那么就是一条直线从上往下平移,第一次碰到左区间中的一个点的时候停止,此时直线的截距乘上 (B) 即为最大值
    于是可以把左区间中的点的上凸壳找出来,然后凸壳上的点 (p_i) 要更新的就是斜率在 ([operatorname{slope}(p_i,p_{i+1}),operatorname{slope}(p_{i-1},p_i)]),拿两个指针扫一遍就行
    当然找最小值就也是同理了,在下凸壳上扫就行

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #define reg register
    #define INT_INF (int)(0x3f3f3f3f)
    #define LL_INF (long long)(0x3f3f3f3f3f3f3f3f)
    #define EN puts("")
    inline long long read(){
    	register long long x=0;register int y=1;register char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    #define N 200006
    #define double long long
    struct Vector{
    	double x,y;
    	inline int operator < (const Vector &b)const{return x==b.x?y<b.y:x<b.x;}
    	inline Vector operator - (const Vector &b)const{return (Vector){x-b.x,y-b.y};}
    	inline double operator * (const Vector &b)const{return x*b.x+y*b.y;}
    	inline double operator ^ (const Vector &b)const{return x*b.y-y*b.x;}
    };
    struct Node{
    	Vector way;int id;
    	inline int operator < (const Node &b)const{return (way^b.way)<0;}
    };
    struct Query{
    	int t;
    	long long a,b,c;
    }Q[N];
    long long max[N],min[N];
    inline void update(reg int id,const Vector &p){
    	long long o=p.x*Q[id].a+p.y*Q[id].b;
    	max[id]=std::max(max[id],o);min[id]=std::min(min[id],o);
    }
    Vector p[N],q[N];
    Node line[N];
    void work(reg int l,reg int r){
    	if(l>=r) return;
    	int mid=(l+r)>>1;
    	work(l,mid);work(mid+1,r);
    	int totL=0,totR=0;
    	for(reg int i=l;i<=mid;i++)if(Q[i].t==1) p[++totL]=(Vector){Q[i].a,Q[i].b};
    	for(reg int i=mid+1;i<=r;i++)if(Q[i].t==2) line[++totR]=(Node){(Vector){Q[i].b,-Q[i].a},i};
    	if(!totL||!totR) return;
    	std::sort(line+1,line+1+totR);
    	std::sort(p+1,p+1+totL);
    	int top=1;q[1]=p[1];
    	for(reg int i=2;i<=totL;i++){
    		while(top>1&&((q[top]-q[top-1])^(p[i]-q[top]))>=0) top--;
    		q[++top]=p[i];
    	}
    	for(reg int i=1,pos=1;i<=top;i++){
    		while(pos<=totR&&(i==top||(line[pos].way^(q[i+1]-q[i]))<=0)) update(line[pos++].id,q[i]);
    	}
    	for(reg int i=1,j=totR;i<j;i++,j--) std::swap(line[i],line[j]);
    	top=1;q[1]=p[1];
    	for(reg int i=2;i<=totL;i++){
    		while(top>1&&((q[top]-q[top-1])^(p[i]-q[top]))<=0) top--;
    		q[++top]=p[i];
    	}
    	for(reg int i=1,pos=1;i<=top;i++){
    		while(pos<=totR&&(i==top||(line[pos].way^(q[i+1]-q[i]))>=0)) update(line[pos++].id,q[i]);
    	}
    }
    int main(){
    //		std::freopen("15.in","r",stdin);
    	int n=read(),q=read()+n;
    	for(reg int i=1;i<=n;i++) Q[i].t=1,Q[i].a=read(),Q[i].b=read();
    	for(reg int i=n+1;i<=q;i++){
    		Q[i].t=read();
    		if(Q[i].t==1) Q[i].a=read(),Q[i].b=read();
    		else{
    			Q[i].a=read();Q[i].b=read();Q[i].c=read();
    			if(Q[i].b<0) Q[i].a=-Q[i].a,Q[i].b=-Q[i].b,Q[i].c=-Q[i].c;
    			max[i]=-2e18;min[i]=2e18;
    		}
    	}
    	work(1,q);
    	for(reg int i=n+1;i<=q;i++)if(Q[i].t==2){
    		puts((max[i]<Q[i].c||min[i]>Q[i].c)?"YES":"NO");
    //			printf("%lld %lld
    ",min[i],max[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    第五篇:在SOUI中使用XML布局属性指引(pos, offset, pos2type)
    第四篇:SOUI资源文件组织
    第三篇:用SOUI能做什么?
    第二篇:SOUI源码的获取及编译
    第一篇:SOUI是什么?
    BuildFilePath 及打开文件对话框
    Java的synchronized关键字:同步机制总结
    Synchronized Methods
    java synchronized详解
    深拷贝与浅拷贝探析
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/14924474.html
Copyright © 2020-2023  润新知