import java.util.* ;
import java.lang.* ;
import java.io.* ;
import java.text.* ;
import java.util.function.* ;
import static java.
lang .
Math .
*;
}
static String humanFloat
( double x
) { return humanFloatFormat.format ( x) ;
}
return sw.toString ( ) ;
}
}
class Vec2 {
public final double x, y;
public Vec2( double x, double y) { this .x = x; this .y = y; }
public static Vec2 Vec2( double x, double y) { return new Vec2( x, y) ; }
public Vec2 add( Vec2 b) { return Vec2( x + b.x , y + b.y ) ; }
public Vec2 sub( Vec2 b) { return Vec2( x - b.x , y - b.y ) ; }
public Vec2 mul( Vec2 b) { return Vec2( x * b.x , y * b.y ) ; }
public Vec2 mul( double b) { return Vec2( x * b, y * b) ; }
public Vec2 div( Vec2 b) { return Vec2( x / b.x , y / b.y ) ; }
public Vec2 div( double b) { return Vec2( x / b, y / b) ; }
@Override
public String toString
( ) { return String .
format ( "(%s, %s)" ,
Util .
humanFloat ( x
) ,
Util .
humanFloat ( y
) ) ; } public Vec2 min
( Vec2 b
) { return Vec2
( Math .
min ( x, b.
x ) ,
Math .
min ( y, b.
y ) ) ; } public Vec2 max
( Vec2 b
) { return Vec2
( Math .
max ( x, b.
x ) ,
Math .
max ( y, b.
y ) ) ; } }
class AABB {
public final Vec2 a, b;
public AABB( Vec2 a, Vec2 b) { this .a = a; this .b = b; }
public static AABB AABB( Vec2 a, Vec2 b) { return new AABB( a, b) ; }
@Override
public String toString
( ) { return String .
format ( "A = %s, B = %s" , a, b
) ; }
public static AABB bound( int count, IntFunction< AABB> ithBB) {
if ( count
<= 0 ) throw Util .
badArgf ( "AABB.bound: count = %d." , count
) ; var bb = ithBB.apply ( 0 ) ;
Vec2 a = bb.a , b = bb.b ;
for ( int i = 1 ; i < count; i++ ) {
bb = ithBB.apply ( i) ;
a = a.min ( bb.a ) ;
b = b.max ( bb.b ) ;
}
return AABB( a, b) ;
}
public static AABB bound( List< AABB> bbs) {
if ( bbs.
size ( ) == 0 ) throw Util .
badArgf ( "AABB.bound: count = %d." , bbs.
size ( ) ) ; var bb = bbs.get ( 0 ) ;
Vec2 a = bb.a , b = bb.b ;
for ( int i = 1 ; i < bbs.size ( ) ; i++ ) {
bb = bbs.get ( i) ;
a = a.min ( bb.a ) ;
b = b.max ( bb.b ) ;
}
return AABB( a, b) ;
}
public static AABB bound( Iterator< AABB> bbs) {
if ( ! bbs.
hasNext ( ) ) throw Util .
badArgf ( "AABB.bound: no items." ) ; var bb = bbs.next ( ) ;
Vec2 a = bb.a , b = bb.b ;
while ( bbs.hasNext ( ) ) {
bb = bbs.next ( ) ;
a = a.min ( bb.a ) ;
b = b.max ( bb.b ) ;
}
return AABB( a, b) ;
}
}
class MyPreciousObject {
AABB bb;
Vec2 pos;
public MyPreciousObject( AABB bb) {
this .bb = bb;
}
}
class Ideone
{
static double benchmark
( String title, Supplier payload
) { return benchmark( title, payload, - 1 ) ;
}
static double benchmark
( String title, Supplier payload,
double reference
) { long start
= System .
nanoTime ( ) ; var payloadResult = payload.get ( ) ;
double time
= ( System .
nanoTime ( ) - start
) * 1e
- 9
; // использовать payloadResult желательно даже без соответствующего %s, а то мало ли СОПТИМИЗИРУЕТСЯ при неиспользовании.
"%s: %.2f s%s%s" ,
title, time, reference
>= 0 ? String .
format ( " (%s)" , judgement
( time, reference
) ) : "" ,
payloadResult
!= null ? String .
format ( "\n %s\n " , payloadResult
) : "" ) ) ; return time;
}
static String judgement
( double time,
double refTime
) { final double absThreshold = 0.1 , relThreshold = .1;
return time <= absThreshold || refTime <= absThreshold ?
String .
format ( "can't judge, min. required time is %.1f s" , absThreshold
) : Math .
max ( time, refTime
) > ( 1 + relThreshold
) * Math .
min ( time, refTime
) ? Math .
abs ( ( time
< refTime
? refTime
/ time
: time
/ refTime
) - 1 ) * 100 ,
time < refTime ? "faster" : "slower" ) :
String .
format ( "no observable difference, min. %.0f%% required" , relThreshold
* 100 ) ; }
static void benchmark( ) {
var objs = new ArrayList< MyPreciousObject> ( ) ;
for ( int i = 0 ; i < 1 _000_000; i++ ) {
Vec2 a = Vec2.Vec2 ( rand.nextDouble ( ) , rand.nextDouble ( ) ) .mul ( 100 ) ;
objs.add ( new MyPreciousObject(
AABB.AABB ( a, a.add ( Vec2.Vec2 ( rand.nextDouble ( ) , rand.nextDouble ( ) ) .mul ( 10 ) ) )
) ) ;
}
var bbList = new ArrayList< AABB> ( ) ;
final int TRIALS = 3 , AMPLIFY = 50 ;
for ( int iTrial = 0 ; iTrial < TRIALS; iTrial++ ) {
System .
out .
printf ( "%s--- TRIAL %d/%d ---\n " , iTrial
> 0 ? "\n " : "" ,
1 + iTrial, TRIALS
) ; var ref = benchmark( "bound(List<AABB>)" , ( ) -> {
AABB result = null ;
for ( int iAmp = 0 ; iAmp < AMPLIFY; iAmp++ ) {
bbList.clear ( ) ;
bbList.ensureCapacity ( objs.size ( ) ) ;
for ( int i = 0 ; i < objs.size ( ) ; i++ )
bbList.add ( objs.get ( i) .bb ) ;
result = AABB.bound ( bbList) ;
}
return result;
} ) ;
benchmark( "bound(int -> AABB)" , ( ) -> {
AABB result = null ;
for ( int iAmp = 0 ; iAmp < AMPLIFY; iAmp++ )
result = AABB.bound ( objs.size ( ) , i -> objs.get ( i) .bb ) ;
return result;
} , ref) ;
benchmark( "bound(List<MyPreciousObject>.map(obj -> AABB).iterator)" , ( ) -> {
AABB result = null ;
for ( int iAmp = 0 ; iAmp < AMPLIFY; iAmp++ )
result = AABB.bound ( objs.stream ( ) .map ( obj -> obj.bb ) .iterator ( ) ) ;
return result;
} , ref) ;
}
}
{
try {
benchmark( ) ;
}
}
}
aW1wb3J0IGphdmEudXRpbC4qOwppbXBvcnQgamF2YS5sYW5nLio7CmltcG9ydCBqYXZhLmlvLio7CmltcG9ydCBqYXZhLnRleHQuKjsKaW1wb3J0IGphdmEudXRpbC5mdW5jdGlvbi4qOwppbXBvcnQgc3RhdGljIGphdmEubGFuZy5NYXRoLio7CgpjbGFzcyBVdGlsIHsKCXN0YXRpYyBJbGxlZ2FsQXJndW1lbnRFeGNlcHRpb24gYmFkQXJnZihTdHJpbmcgZm10LCBPYmplY3QuLi4gYXJncykgewoJCXJldHVybiBuZXcgSWxsZWdhbEFyZ3VtZW50RXhjZXB0aW9uKFN0cmluZy5mb3JtYXQoZm10LCBhcmdzKSk7Cgl9CgoJc3RhdGljIGZpbmFsIERlY2ltYWxGb3JtYXQgaHVtYW5GbG9hdEZvcm1hdCA9IG5ldyBEZWNpbWFsRm9ybWF0KCIjLiMjIyIpOwoKCXN0YXRpYyBTdHJpbmcgaHVtYW5GbG9hdChkb3VibGUgeCkgewoJCXJldHVybiBodW1hbkZsb2F0Rm9ybWF0LmZvcm1hdCh4KTsKCX0KCglzdGF0aWMgU3RyaW5nIHRyYWNlKEV4Y2VwdGlvbiBlKSB7CgkJU3RyaW5nV3JpdGVyIHN3ID0gbmV3IFN0cmluZ1dyaXRlcigpOwoJCWUucHJpbnRTdGFja1RyYWNlKG5ldyBQcmludFdyaXRlcihzdykpOwoJCXJldHVybiBzdy50b1N0cmluZygpOwoJfQp9CgpjbGFzcyBWZWMyIHsKCXB1YmxpYyBmaW5hbCBkb3VibGUgeCwgeTsKCXB1YmxpYyBWZWMyKGRvdWJsZSB4LCBkb3VibGUgeSkgeyB0aGlzLnggPSB4OyB0aGlzLnkgPSB5OyB9CglwdWJsaWMgc3RhdGljIFZlYzIgVmVjMihkb3VibGUgeCwgZG91YmxlIHkpIHsgcmV0dXJuIG5ldyBWZWMyKHgsIHkpOyB9CglwdWJsaWMgVmVjMiBhZGQoVmVjMiBiKSB7IHJldHVybiBWZWMyKHggKyBiLngsIHkgKyBiLnkpOyB9CglwdWJsaWMgVmVjMiBzdWIoVmVjMiBiKSB7IHJldHVybiBWZWMyKHggLSBiLngsIHkgLSBiLnkpOyB9CglwdWJsaWMgVmVjMiBtdWwoVmVjMiBiKSB7IHJldHVybiBWZWMyKHggKiBiLngsIHkgKiBiLnkpOyB9CglwdWJsaWMgVmVjMiBtdWwoZG91YmxlIGIpIHsgcmV0dXJuIFZlYzIoeCAqIGIsIHkgKiBiKTsgfQoJcHVibGljIFZlYzIgZGl2KFZlYzIgYikgeyByZXR1cm4gVmVjMih4IC8gYi54LCB5IC8gYi55KTsgfQoJcHVibGljIFZlYzIgZGl2KGRvdWJsZSBiKSB7IHJldHVybiBWZWMyKHggLyBiLCB5IC8gYik7IH0KCUBPdmVycmlkZSBwdWJsaWMgU3RyaW5nIHRvU3RyaW5nKCkgeyByZXR1cm4gU3RyaW5nLmZvcm1hdCgiKCVzLCAlcykiLCBVdGlsLmh1bWFuRmxvYXQoeCksIFV0aWwuaHVtYW5GbG9hdCh5KSk7IH0KCXB1YmxpYyBWZWMyIG1pbihWZWMyIGIpIHsgcmV0dXJuIFZlYzIoTWF0aC5taW4oeCwgYi54KSwgTWF0aC5taW4oeSwgYi55KSk7IH0KCXB1YmxpYyBWZWMyIG1heChWZWMyIGIpIHsgcmV0dXJuIFZlYzIoTWF0aC5tYXgoeCwgYi54KSwgTWF0aC5tYXgoeSwgYi55KSk7IH0KfQoKY2xhc3MgQUFCQiB7CglwdWJsaWMgZmluYWwgVmVjMiBhLCBiOwoJcHVibGljIEFBQkIoVmVjMiBhLCBWZWMyIGIpIHsgdGhpcy5hID0gYTsgdGhpcy5iID0gYjsgfQoJcHVibGljIHN0YXRpYyBBQUJCIEFBQkIoVmVjMiBhLCBWZWMyIGIpIHsgcmV0dXJuIG5ldyBBQUJCKGEsIGIpOyB9CglAT3ZlcnJpZGUgcHVibGljIFN0cmluZyB0b1N0cmluZygpIHsgcmV0dXJuIFN0cmluZy5mb3JtYXQoIkEgPSAlcywgQiA9ICVzIiwgYSwgYik7IH0KCglwdWJsaWMgc3RhdGljIEFBQkIgYm91bmQoaW50IGNvdW50LCBJbnRGdW5jdGlvbjxBQUJCPiBpdGhCQikgewoJCWlmIChjb3VudCA8PSAwKSB0aHJvdyBVdGlsLmJhZEFyZ2YoIkFBQkIuYm91bmQ6IGNvdW50ID0gJWQuIiwgY291bnQpOwoJCXZhciBiYiA9IGl0aEJCLmFwcGx5KDApOwoJCVZlYzIgYSA9IGJiLmEsIGIgPSBiYi5iOwoJCWZvciAoaW50IGkgPSAxOyBpIDwgY291bnQ7IGkrKykgewoJCQliYiA9IGl0aEJCLmFwcGx5KGkpOwoJCQlhID0gYS5taW4oYmIuYSk7CgkJCWIgPSBiLm1heChiYi5iKTsKCQl9CgkJcmV0dXJuIEFBQkIoYSwgYik7Cgl9CgoJcHVibGljIHN0YXRpYyBBQUJCIGJvdW5kKExpc3Q8QUFCQj4gYmJzKSB7CgkJaWYgKGJicy5zaXplKCkgPT0gMCkgdGhyb3cgVXRpbC5iYWRBcmdmKCJBQUJCLmJvdW5kOiBjb3VudCA9ICVkLiIsIGJicy5zaXplKCkpOwoJCXZhciBiYiA9IGJicy5nZXQoMCk7CgkJVmVjMiBhID0gYmIuYSwgYiA9IGJiLmI7CgkJZm9yIChpbnQgaSA9IDE7IGkgPCBiYnMuc2l6ZSgpOyBpKyspIHsKCQkJYmIgPSBiYnMuZ2V0KGkpOwoJCQlhID0gYS5taW4oYmIuYSk7CgkJCWIgPSBiLm1heChiYi5iKTsKCQl9CgkJcmV0dXJuIEFBQkIoYSwgYik7Cgl9CgoJcHVibGljIHN0YXRpYyBBQUJCIGJvdW5kKEl0ZXJhdG9yPEFBQkI+IGJicykgewoJCWlmICghYmJzLmhhc05leHQoKSkgdGhyb3cgVXRpbC5iYWRBcmdmKCJBQUJCLmJvdW5kOiBubyBpdGVtcy4iKTsKCQl2YXIgYmIgPSBiYnMubmV4dCgpOwoJCVZlYzIgYSA9IGJiLmEsIGIgPSBiYi5iOwoJCXdoaWxlIChiYnMuaGFzTmV4dCgpKSB7CgkJCWJiID0gYmJzLm5leHQoKTsKCQkJYSA9IGEubWluKGJiLmEpOwoJCQliID0gYi5tYXgoYmIuYik7CgkJfQoJCXJldHVybiBBQUJCKGEsIGIpOwoJfQp9CgpjbGFzcyBNeVByZWNpb3VzT2JqZWN0IHsKCUFBQkIgYmI7CglWZWMyIHBvczsKCVN0cmluZyBuYW1lOwoJT2JqZWN0IHNvbWVPdGhlckRhdGE7CgoJcHVibGljIE15UHJlY2lvdXNPYmplY3QoQUFCQiBiYikgewoJCXRoaXMuYmIgPSBiYjsKCX0KfQoKY2xhc3MgSWRlb25lCnsKCXN0YXRpYyBkb3VibGUgYmVuY2htYXJrKFN0cmluZyB0aXRsZSwgU3VwcGxpZXIgcGF5bG9hZCkgewoJCXJldHVybiBiZW5jaG1hcmsodGl0bGUsIHBheWxvYWQsIC0xKTsKCX0KCglzdGF0aWMgZG91YmxlIGJlbmNobWFyayhTdHJpbmcgdGl0bGUsIFN1cHBsaWVyIHBheWxvYWQsIGRvdWJsZSByZWZlcmVuY2UpIHsKCQlsb25nIHN0YXJ0ID0gU3lzdGVtLm5hbm9UaW1lKCk7CgkJdmFyIHBheWxvYWRSZXN1bHQgPSBwYXlsb2FkLmdldCgpOwoJCWRvdWJsZSB0aW1lID0gKFN5c3RlbS5uYW5vVGltZSgpIC0gc3RhcnQpICogMWUtOTsKCQkvLyDQuNGB0L/QvtC70YzQt9C+0LLQsNGC0YwgcGF5bG9hZFJlc3VsdCDQttC10LvQsNGC0LXQu9GM0L3QviDQtNCw0LbQtSDQsdC10Lcg0YHQvtC+0YLQstC10YLRgdGC0LLRg9GO0YnQtdCz0L4gJXMsINCwINGC0L4g0LzQsNC70L4g0LvQuCDQodCe0J/QotCY0JzQmNCX0JjQoNCj0JXQotCh0K8g0L/RgNC4INC90LXQuNGB0L/QvtC70YzQt9C+0LLQsNC90LjQuC4KCQlTeXN0ZW0ub3V0LnByaW50bG4oU3RyaW5nLmZvcm1hdCgKCQkJIiVzOiAlLjJmIHMlcyVzIiwKCQkJdGl0bGUsIHRpbWUsIHJlZmVyZW5jZSA+PSAwID8gU3RyaW5nLmZvcm1hdCgiICglcykiLCBqdWRnZW1lbnQodGltZSwgcmVmZXJlbmNlKSkgOiAiIiwKCQkJcGF5bG9hZFJlc3VsdCAhPSBudWxsID8gU3RyaW5nLmZvcm1hdCgiXG4lc1xuIiwgcGF5bG9hZFJlc3VsdCkgOiAiIikpOwoJCXJldHVybiB0aW1lOwoJfQoKCXN0YXRpYyBTdHJpbmcganVkZ2VtZW50KGRvdWJsZSB0aW1lLCBkb3VibGUgcmVmVGltZSkgewoJCWZpbmFsIGRvdWJsZSBhYnNUaHJlc2hvbGQgPSAwLjEsIHJlbFRocmVzaG9sZCA9IC4xOwoKCQlyZXR1cm4gdGltZSA8PSBhYnNUaHJlc2hvbGQgfHwgcmVmVGltZSA8PSBhYnNUaHJlc2hvbGQgPwoJCQlTdHJpbmcuZm9ybWF0KCJjYW4ndCBqdWRnZSwgbWluLiByZXF1aXJlZCB0aW1lIGlzICUuMWYgcyIsIGFic1RocmVzaG9sZCkgOgoJCQlNYXRoLm1heCh0aW1lLCByZWZUaW1lKSA+ICgxICsgcmVsVGhyZXNob2xkKSAqIE1hdGgubWluKHRpbWUsIHJlZlRpbWUpID8KCQkJU3RyaW5nLmZvcm1hdCgiJS4wZiUlICVzIiwKCQkJCU1hdGguYWJzKCh0aW1lIDwgcmVmVGltZSA/IHJlZlRpbWUgLyB0aW1lIDogdGltZSAvIHJlZlRpbWUpIC0gMSkgKiAxMDAsCgkJCQl0aW1lIDwgcmVmVGltZSA/ICJmYXN0ZXIiIDogInNsb3dlciIpIDoKCQkJU3RyaW5nLmZvcm1hdCgibm8gb2JzZXJ2YWJsZSBkaWZmZXJlbmNlLCBtaW4uICUuMGYlJSByZXF1aXJlZCIsIHJlbFRocmVzaG9sZCAqIDEwMCk7Cgl9CgoJc3RhdGljIHZvaWQgYmVuY2htYXJrKCkgewoJCXZhciBvYmpzID0gbmV3IEFycmF5TGlzdDxNeVByZWNpb3VzT2JqZWN0PigpOwoJCXZhciByYW5kID0gbmV3IFJhbmRvbSgxKTsKCQlmb3IgKGludCBpID0gMDsgaSA8IDFfMDAwXzAwMDsgaSsrKSB7CgkJCVZlYzIgYSA9IFZlYzIuVmVjMihyYW5kLm5leHREb3VibGUoKSwgcmFuZC5uZXh0RG91YmxlKCkpLm11bCgxMDApOwoJCQlvYmpzLmFkZChuZXcgTXlQcmVjaW91c09iamVjdCgKCQkJCUFBQkIuQUFCQihhLCBhLmFkZChWZWMyLlZlYzIocmFuZC5uZXh0RG91YmxlKCksIHJhbmQubmV4dERvdWJsZSgpKS5tdWwoMTApKSkKCQkJKSk7CgkJfQoJCXZhciBiYkxpc3QgPSBuZXcgQXJyYXlMaXN0PEFBQkI+KCk7CgoJCWZpbmFsIGludCBUUklBTFMgPSAzLCBBTVBMSUZZID0gNTA7CgkJZm9yIChpbnQgaVRyaWFsID0gMDsgaVRyaWFsIDwgVFJJQUxTOyBpVHJpYWwrKykgewoJCQlTeXN0ZW0ub3V0LnByaW50ZigiJXMtLS0gVFJJQUwgJWQvJWQgLS0tXG4iLCBpVHJpYWwgPiAwID8gIlxuIiA6ICIiLCAxICsgaVRyaWFsLCBUUklBTFMpOwoJCQl2YXIgcmVmID0gYmVuY2htYXJrKCJib3VuZChMaXN0PEFBQkI+KSIsICgpIC0+IHsKCQkJCUFBQkIgcmVzdWx0ID0gbnVsbDsKCQkJCWZvciAoaW50IGlBbXAgPSAwOyBpQW1wIDwgQU1QTElGWTsgaUFtcCsrKSB7CgkJCQkJYmJMaXN0LmNsZWFyKCk7CgkJCQkJYmJMaXN0LmVuc3VyZUNhcGFjaXR5KG9ianMuc2l6ZSgpKTsKCQkJCQlmb3IgKGludCBpID0gMDsgaSA8IG9ianMuc2l6ZSgpOyBpKyspCgkJCQkJCWJiTGlzdC5hZGQob2Jqcy5nZXQoaSkuYmIpOwoJCQkJCXJlc3VsdCA9IEFBQkIuYm91bmQoYmJMaXN0KTsKCQkJCX0KCQkJCXJldHVybiByZXN1bHQ7CgkJCX0pOwoKCQkJYmVuY2htYXJrKCJib3VuZChpbnQgLT4gQUFCQikiLCAoKSAtPiB7CgkJCQlBQUJCIHJlc3VsdCA9IG51bGw7CgkJCQlmb3IgKGludCBpQW1wID0gMDsgaUFtcCA8IEFNUExJRlk7IGlBbXArKykKCQkJCQlyZXN1bHQgPSBBQUJCLmJvdW5kKG9ianMuc2l6ZSgpLCBpIC0+IG9ianMuZ2V0KGkpLmJiKTsKCQkJCXJldHVybiByZXN1bHQ7CgkJCX0sIHJlZik7CgoJCQliZW5jaG1hcmsoImJvdW5kKExpc3Q8TXlQcmVjaW91c09iamVjdD4ubWFwKG9iaiAtPiBBQUJCKS5pdGVyYXRvcikiLCAoKSAtPiB7CgkJCQlBQUJCIHJlc3VsdCA9IG51bGw7CgkJCQlmb3IgKGludCBpQW1wID0gMDsgaUFtcCA8IEFNUExJRlk7IGlBbXArKykKCQkJCQlyZXN1bHQgPSBBQUJCLmJvdW5kKG9ianMuc3RyZWFtKCkubWFwKG9iaiAtPiBvYmouYmIpLml0ZXJhdG9yKCkpOwoJCQkJcmV0dXJuIHJlc3VsdDsKCQkJfSwgcmVmKTsKCQl9Cgl9CgoJcHVibGljIHN0YXRpYyB2b2lkIG1haW4gKFN0cmluZ1tdIGFyZ3MpIHRocm93cyBqYXZhLmxhbmcuRXhjZXB0aW9uCgl7CgkJdHJ5IHsKCQkJYmVuY2htYXJrKCk7CgkJfSBjYXRjaCAoRXhjZXB0aW9uIGUpIHsKCQkJU3lzdGVtLm91dC5wcmludGxuKFV0aWwudHJhY2UoZSkpOwoJCX0KCX0KfQ==