Loading

辣鸡(myself)

这个题考场上挂惨了,写的跟正解思路一样,但是没写纵向判断,没删调试信息,没开\(long \ long\)
这个题正解不算太难,就看能不能静下心来推一推了。
这个没有题解帮的了你,只有自己推出来才是自己的。

先说玄学\(n^2\)剪枝做法。
首先需要按横坐标排序,然后需要\(O(1)\)判断两个矩形之间连的键数。
和许多人不同,我直接分一根键和两跟键讨论,因为我觉得这样简单(虽然没人认同OvO)
直接粘个代码,没什么思路。

code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long long
#define R register int
#define printf Ruusupuu = printf

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef unsigned long long G ;
const int N = 1e5 + 10 ;

int Ruusupuu ;

inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch ^ '0' ) , ch = getchar() ;
	return fg ? -w : w ;
}

int n , m ; L ans ;
struct E{ int x , y , xx , yy ; } b [N] ;

inline bool cmp( E a , E b ){ return ( a.x == b.x ) ? a.y < b.y : a.x < b.x ; }
inline bool csp( E a , E b ){ return ( a.y == b.y ) ? a.x < b.x : a.y < b.y ; }

inline L ct( int x , int xx , int y , int yy ){
	return 2ll * ( xx - x ) * ( yy - y ) ;
}

void sc(){
	n = read() ;
	for( R i = 1 ; i <= n ; i ++ ){
		b [i].x = read() + 1 , b [i].y = read() + 1 ;
		b [i].xx = read() + 1 , b [i].yy = read() + 1 ;
		ans += ct( b [i].x , b [i].xx , b [i].y , b [i].yy ) ;
	}
}

inline L get( int x , int y ){
	int xx1 = b [x].x , xx2 = b [x].xx , xy1 = b [x].y , xy2 = b [x].yy ;
	int yx1 = b [y].x , yx2 = b [y].xx , yy1 = b [y].y , yy2 = b [y].yy ;
	if( xx2 + 1 < yx1 ) return 0 ;
	if( xx2 + 1 == yx1 ){
		L ans = 0 ;
		if( ( yy2 > xy1 && yy2 < xy2 ) || ( yy1 > xy1 && yy2 < xy2 ) ) ans += 2 * ( min( yy2 , xy2 - 1 ) - max( yy1 , xy1 - 1 ) + 1 ) ;  
		if( xy2 != xy1 && xy1 >= yy1 && xy1 <= yy2 ) ans ++ ;
		if( xy2 != xy1 && xy2 >= yy1 && xy2 <= yy2 ) ans ++ ;
		if( xy2 + 1 >= yy1 && xy2 + 1 <= yy2 ) ans ++ ;
		if( xy1 - 1 >= yy1 && xy1 - 1 <= yy2 ) ans ++ ;
		return ans ;
	} 
	
	if( xy2 + 1 == yy1 || xy1 - 1 == yy2 ){
		L ans = 0 ;
		if( ( xx2 > yx2 && xx1 < yx2 ) || ( xx2 > yx1 && xx1 < yx2 ) ) ans += 2 * ( min( xx2 - 1 , yx2 ) - max( xx1 + 1 , yx1 ) + 1 ) ;
		if( xx1 != xx2 && xx1 >= yx1 && xx1 <= yx2 ) ans ++ ;
		if( xx1 != xx2 && xx2 >= yx1 && xx2 <= yx2 ) ans ++ ;
		if( xx1 - 1 >= yx1 && xx1 - 1 <= yx2 ) ans ++ ;
		if( xx2 + 1 >= yx1 && xx2 + 1 <= yx2 ) ans ++ ;
 		return ans ;
 	} return 0 ;
}

void work(){
	sort( b + 1 , b + 1 + n , cmp ) ;
	for( R i = 1 ; i < n ; i ++ ){
		for( R j = i + 1 ; j <= n ; j ++ ){
			if( b [j].x > b [i].xx + 1 ) break ;
			ans += get( i , j ) ;
		}		
	} 
	printf( "%lld\n" , ans ) ;
} 

signed main(){	
	sc() ;
	work() ;
	return 0 ;
}

还有一种\(nlog^2n\)的双排序二分倍增做法,主要是建立在推出两个矩形某个方向连键数就是重合的长度乘2,如果重合的是端点需要特判。

code


#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long
#define R register int
#define printf Ruusupuu = printf

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef unsigned long long G ;
const int N = 1e5 + 10 ;

int Ruusupuu ;

inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch ^ '0' ) , ch = getchar() ;
	return fg ? -w : w ;
}

int n , m ; L ans ;
struct E{ int x , y , xx , yy ; } b [N] ;

inline bool cmp( E a , E b ){ return ( a.x == b.x ) ? a.y < b.y : a.x < b.x ; }
inline bool csp( E a , E b ){ return ( a.y == b.y ) ? a.x < b.x : a.y < b.y ; }

inline L ct( int x , int xx , int y , int yy ){
	return 2ll * ( xx - x ) * ( yy - y ) ;
}

void sc(){
	n = read() ;
	for( R i = 1 ; i <= n ; i ++ ){
		b [i].x = read() + 1 , b [i].y = read() + 1 ;
		b [i].xx = read() + 1 , b [i].yy = read() + 1 ;
		ans += ct( b [i].x , b [i].xx , b [i].y , b [i].yy ) ;
	}
}

void work(){
	sort( b + 1 , b + 1 + n , cmp ) ;
	for( R i = 1 ; i < n ; i ++ ){
		
		int j = i , r = n ;
		while( j < r ){
			int mid = ( j + r ) >> 1 ;
			if( b [mid].x > b [i].xx ) r = mid ;
			else j = mid + 1 ;
		}		
		
		if( b [j].x != b [i].xx + 1 ) continue ;
		
		while( j <= n && b [j].x == b [i].xx + 1 && b [j].yy < b [i].y - 1 ) j ++ ;
		
		if( j > n || b [j].x != b [i].xx + 1 ) continue ;
		
		for( ; j <= n && b [j].x == b [i].xx + 1 && b [j].y <= b [i].yy + 1 ; j ++ ){
			int len = ( min( b [i].yy , b [j].yy ) - max( b [i].y , b [j].y ) + 1 ) ;
			if( len ) ans += 2 * ( len - 1 ) + ( b [i].yy != b [j].y ) + ( b [i].y != b [j].yy ) ;
			else ans ++ ;
		}		
		
	} //printf( "%lld\n" , ans ) ;
	sort( b + 1 , b + 1 + n , csp ) ;
	for( R i = 1 ; i < n ; i ++ ){
		//for( R j = i + 1 ; j <= n ; j ++ ){
		int j = i , r = n ;
		while( j < r ){
			int mid = ( j + r ) >> 1 ;
			if( b [mid].y > b [i].yy ) r = mid ;
			else j = mid + 1 ;
		}
	
		if( b [j].y != b [i].yy + 1 || !j ) continue ;
		
	//	while( j <= n && b [j].y == b [i].yy + 1 && b [j].xx < b [i].x - 1 ) j ++ ;
		
		int gap = 1 ;
		
		while( j <= n && b [j].y == b [i].yy + 1 && b [j].xx < b [i].x - 1 ){
			int zt = j + gap ;
		//	printf( "%ld\n" , zt ) ;
			if( zt <= n && b [zt].y == b [i].yy + 1 && b [zt].xx < b [i].x - 1 ) j += gap , gap *= 2 ;
			else gap /= 2 , j ++ ;
		}
		
		if( j > n || b [j].y != b [i].yy + 1 ) continue ;
		
		for( ; j <= n && b [j].y == b [i].yy + 1 && b [j].x <= b [i].xx + 1 ; j ++ ){
			int len = ( min ( b [i].xx , b [j].xx ) - max( b [i].x , b [j].x ) + 1 ) ;
			if( len ) ans += 2 * ( len - 1 ) + ( b [i].xx != b [j].x ) + ( b [i].x != b [j].xx ) ;
		}
		 
	}
	printf( "%lld\n" , ans ) ;
} 

signed main(){	
	sc() ;
	work() ;
	return 0 ;
}

posted @ 2021-06-12 21:19  Soresen  阅读(214)  评论(0)    收藏  举报