UVALive 6041 Retrenchment
不容易,kd-tree。。终于过了,wa了好久,然后快两个月没管它,今天终于过了。
题目意思很简单,然后做法就是用kd-tree找最邻近的点和次邻近的点。
有几个坑点,就是点积和叉积会爆int,然后就是我的几何模板挫了,点在线段上,由于没有判断点是否会和线段的端点重合,我一直wa。下午重新看题的时候突然想到这个点,哎。。总算过了,好开心。。
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define LL long long #define mnx 21100 #define eps 1e-8 #define mod 1000000007 struct point{ int x, y, id; point( int x = 0, int y = 0 ) : x(x), y(y) {} point operator + ( const point &b ) const { return point( x + b.x, y + b.y ); } point operator - ( const point &b ) const { return point( x - b.x, y - b.y ); } LL len(){ return (LL)x * x + (LL)y * y; } bool operator == ( const point &b ) const { return x == b.x && y == b.y; } }; LL dot( point a, point b ){ return (LL)a.x * b.x + (LL)a.y * b.y; } LL cross( point a, point b ){ return (LL)a.x * b.y - (LL)a.y * b.x; } LL sqr( int x ){ return (LL)x * x; } bool on_segment( point p, point a1, point a2 ){ if( p == a1 || p == a2 ) return true; return cross( a1 - p, a2 - p ) == 0 && dot( a1 - p, a2 - p ) < 0; } int point_in_polygon( point p, point *poly, int n ){ int wn = 0; poly[n] = poly[0]; for( int i = 0; i < n; ++i ){ if( on_segment( p, poly[i], poly[i+1] ) ) return 1; LL k = cross( poly[i+1] - poly[i], p - poly[i] ); int d1 = poly[i].y - p.y, d2 = poly[i+1].y - p.y; if( k > 0 && d1 <= 0 && d2 > 0 ) wn++; if( k < 0 && d2 <= 0 && d1 > 0 ) wn--; } if( wn != 0 ) return 1; return 0; } bool cmpX( point a, point b ){ return a.x<b.x || (a.x==b.x&&a.y<b.y) || (a.x==b.x&&a.y==b.y&&a.id<b.id); } bool cmpY( point a, point b ){ return a.y<b.y || (a.y==b.y&&a.x<b.x) || (a.y==b.y&&a.x==b.x&&a.id<b.id); } bool cmp( point a, point b, bool div ){ return div ? cmpY( a, b ) : cmpX( a, b ); } struct node{ point val; node *ls; node *rs; bool exist, div; }; node *root; point in[mnx], ans; LL dis; node *build( int l, int r, bool div ){ if( l >= r ) return NULL; int m = ( l + r ) >> 1; nth_element( in + l, in + m, in + r, div ? cmpY : cmpX ); node *now = new node(); now->val = in[m], now->exist = 1, now->div = div; now->ls = build( l, m, div & 1 ); now->rs = build( m+1, r, div & 1 ); return now; } void search( node *a, point d ){ if( a == NULL ) return; if( a->exist ){ LL dd = ( d-a->val).len(); if( dis>dd || (dis==dd && ans.id > a->val.id) ) ans = a->val, dis = dd; } if( cmp( d, a->val, a->div ) ){ search( a->ls, d ); if( a->div ? sqr( a->val.y - d.y ) <= dis : sqr( a->val.x - d.x ) <= dis ) search( a->rs, d ); } else{ search( a->rs, d ); if( a->div ? sqr( a->val.y - d.y ) <= dis : sqr( a->val.x - d.x ) <= dis ) search( a->ls, d ); } } void erase( node *a, point tmp ){ if( a->val.id == tmp.id ){ a->exist = 0; return ; } if( cmp( tmp, a->val, a->div ) ) erase( a->ls, tmp ); else erase( a->rs, tmp ); } void insert( node *a, point tmp ){ if( a->val.id == tmp.id ){ a->exist = 1; return ; } if( cmp( tmp, a->val, a->div ) ) insert( a->ls, tmp ); else insert( a->rs, tmp ); } point p[mnx], pp[mnx]; int main(){ freopen( "tt.txt", "r", stdin ); int cas, kk = 1; scanf( "%d", &cas ); while( cas-- ){ printf( "Case #%d:\n", kk++ ); int n; scanf( "%d", &n ); for( int i = 1; i <= n; ++i ){ scanf( "%d%d", &p[i].x, &p[i].y ); p[i].id = i; } int R, B, Q; scanf( "%d", &R ); for( int cnt = 1; cnt <= R; ++cnt ){ printf( "Region %d\n", cnt ); scanf( "%d", &B ); for( int i = 0; i < B; ++i ) scanf( "%d%d",&pp[i].x, &pp[i].y ); int all = 0; for( int i = 1; i <= n; ++i ){ if( point_in_polygon( p[i], pp, B ) ) in[all++] = p[i]; } root = build( 0, all, 0 ); scanf( "%d", &Q ); point q; while( Q-- ){ scanf( "%d%d", &q.x, &q.y ); dis = 1000000000000000; search( root, q ); point tmp = ans; printf( "%d ", ans.id ); erase( root, tmp ); dis = 1000000000000000; search( root, q ); printf( "%d\n", ans.id); insert( root, tmp ); } } } return 0; }