zoukankan      html  css  js  c++  java
  • 「JSOI2018」战争

    题目链接

    题目大意

    本题解中向量与点互通。

    题目大概就是判断一个凸包(B)平移(overrightarrow v)之后是否与凸包(A)有相交。相交即(exists b in B, b + overrightarrow v =ain A)

    如果转换一下,就是(exists b in B, ain A, a - b = overrightarrow v)。等价于(S={a-b,ain A,bin B},overrightarrow v in S)

    闵可夫斯基和:对于点集(A)(B),定义他们的闵可夫斯基和(A+B={a+b, ain A, b in B})。更多的闵可夫斯基和相关和计算几何相关会在以后的博客中详细介绍,这里先挖个坑。

    于是这道题就是求两个点集闵可夫斯基和的凸包,然后判断一个点是否在凸包内。而两个凸包的闵可夫斯基和的凸包可以在(O(n+m))之内得到,于是这题就是(O(qlog n +nlog n))

    参考程序

    #pragma GCC diagnostic error "-std=c++17"
    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    
    const LL Maxn = 100010;
    struct point {
    	LL x, y;
    	point() {};
    	point( LL _x, LL _y ) : x( _x ), y( _y ) {}
    	point operator + ( const point Other ) const {
    		point Ans( x + Other.x, y + Other.y );
    		return Ans;
    	}
    	point operator - ( const point Other ) const {
    		point Ans( x - Other.x, y - Other.y );
    		return Ans;
    	}
    	bool operator == ( const point Other ) const {
    		return x == Other.x && y == Other.y;
    	}
    };
    point Standard;
    LL Cross( point A, point B ) {
    	return A.x * B.y - B.x * A.y;
    }
    LL Cross( point A, point B, point C ) {
    	return ( A.x - C.x ) * ( B.y - C.y ) - ( B.x - C.x ) * ( A.y - C.y );
    }
    bool Cmp1( point X, point Y ) {
    	return X.y < Y.y || X.y == Y.y && X.x < Y.x;
    }
    bool Cmp2( point X, point Y ) {
    	LL T = Cross( X, Y, Standard );
    	return T > 0LL || T == 0LL && X.x - Standard.x < Y.x - Standard.x;
    }
    LL Stack[ Maxn ], Num;
    struct pointSet {
    	LL Size;
    	point A[ Maxn << 2 ];
    	inline void Print() {
    		printf( "Size : %lld
    ", Size );
    		for( int i = 1; i <= Size; ++i ) printf( "%lld %lld
    ", A[ i ].x, A[ i ].y );
    		return;
    	}
    	void Collet() {
    		sort( A + 1, A + Size + 1, Cmp1 );
    		Standard = A[ 1 ];
    		sort( A + 2, A + Size + 1, Cmp2 );
    		Num = 2; Stack[ 1 ] = 1; Stack[ 2 ] = 2;
    		for( LL i = 3; i <= Size; ++i ) {
    			for( ; Num > 1 && Cross( A[ i ], A[ Stack[ Num ] ], A[ Stack[ Num - 1 ] ] ) >= 0LL; --Num );
    			Stack[ ++Num ] = i;
    		}
    		for( LL i = 1; i <= Num; ++i ) A[ i ] = A[ Stack[ i ] ]; Size = Num;
    		return;
    	}
    };
    LL q;
    pointSet A, B, C;
    point T;
    
    bool Test( LL Left, LL Right ) {
    	if( Left + 1 == Right ) {
    		return Cross( T, C.A[ Left ], C.A[ Right ] ) >= 0;
    	}
    	LL Mid = ( Left + Right ) >> 1;
    	if( Cross( C.A[ Mid ], T, C.A[ 1 ] ) >= 0 ) return Test( Mid, Right ); else return Test( Left, Mid );
    }
    
    int main() {
    	scanf( "%lld%lld%lld", &A.Size, &B.Size, &q );
    	for( LL i = 1; i <= A.Size; ++i ) scanf( "%lld%lld", &A.A[ i ].x, &A.A[ i ].y );
    	for( LL i = 1; i <= B.Size; ++i ) scanf( "%lld%lld", &B.A[ i ].x, &B.A[ i ].y );
    	for( LL i = 1; i <= B.Size; ++i ) B.A[ i ].x = -B.A[ i ].x, B.A[ i ].y  = -B.A[ i ].y;
    	A.Collet(); B.Collet();
    	A.A[ ++A.Size ] = A.A[ 1 ]; B.A[ ++B.Size ] = B.A[ 1 ];
    	C.Size = 0;
    	C.A[ ++C.Size ] = A.A[ 1 ] + B.A[ 1 ];
    	LL i1 = 2, i2 = 2;
    	for( ; i1 <= A.Size && i2 <= B.Size; ) {
    		if( Cross( A.A[ i1 ] - A.A[ i1 - 1 ], B.A[ i2 ] - B.A[ i2 - 1 ] ) >= 0LL ) {
    			C.A[ C.Size + 1 ] = C.A[ C.Size ] + ( A.A[ i1 ] - A.A[ i1 - 1 ] );
    			++i1; ++C.Size;
    		} else {
    			C.A[ C.Size + 1 ] = C.A[ C.Size ] + ( B.A[ i2 ] - B.A[ i2 - 1 ] );
    			++i2; ++C.Size;
    		}
    	}
    	for( ; i1 <= A.Size; ++i1 ) C.A[ C.Size + 1 ] = C.A[ C.Size ] + ( A.A[ i1 ] - A.A[ i1 - 1 ] ), ++C.Size;
    	for( ; i2 <= B.Size; ++i2 ) C.A[ C.Size + 1 ] = C.A[ C.Size ] + ( B.A[ i2 ] - B.A[ i2 - 1 ] ), ++C.Size;
    	Standard = C.A[ 1 ];
    	for( LL i = 1; i <= q; ++i ) {
    		scanf( "%lld%lld", &T.x, &T.y );
    		if( Cross( C.A[ C.Size ], T, C.A[ 1 ] ) > 0LL || Cross( T, C.A[ 2 ], C.A[ 1 ] ) > 0LL ) {
    			printf( "0
    " );
    			continue;
    		}
    		if( T == C.A[ 1 ] || Test( 2, C.Size ) ) printf( "1
    " ); else printf( "0
    " );
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    使用Spring Cloud Feign作为HTTP客户端调用远程HTTP服务
    聊聊高并发系统之限流特技
    Java程序员 必须掌握的 20+ 种 Spring 常用注解
    这20个核心技术,作为Java开发程序员,你一定要掌握
    40K刚面完Java岗,这些技术必须掌握
    Java 5,6,7,8,9,10,11新特性超详细总结
    小米程序员的忧虑:感觉互联网这两年要凉,想回家种地
    Java技术文档—Java中的运算符有哪些?
    Java笔记之数组,异常处理,集合知识要点
    Java学习笔记——IO流基础知识点整理
  • 原文地址:https://www.cnblogs.com/chy-2003/p/11265803.html
Copyright © 2011-2022 走看看