辣鸡(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 ;
}
$The \ light \ has \ betrayed \ me$

浙公网安备 33010602011771号