Solution -「多校联训」最大面积
\(\mathcal{Description}\)
Link.
平面上有 \(n\) 个点 \(A_{1..n}\),\(q\) 次询问,每次给出点 \(P\),求
\]
\(n\le10^5\),\(q\le10^6\)。
\(\mathcal{Solution}\)
初步转化一下式子:
\sum_{i=l}^r\vec{OP}\times\vec{OA_i}&=\sum_{i=l}^r(x_Py_{A_i}-y_Px_{A_i})\\
&=x_P\left(\sum_{i=l}^ry_{A_i}-\frac{y_P}{x_P}\sum_{i=l}^rx_{A_i}\right)~~~~(x_P\not=0)
\end{aligned}
\]
对于 \(x_P=0\) 即求 \(x_{A_{1..n}}\) 的最大子段和;对于 \(x_P\not=0\),提出 \(x_P\) 后,记 \(k=\frac{y_P}{x_P}\),\(y(l,r)=\sum_{i=l}^ry_{A_i}\),\(x(l,r)=\sum_{i=l}^rx_{A_i}\),原式可以看作
\]
并要求最大化 \(x_Pb\)。相当于过某个 \((x(l,r),y(l,r))\) 作斜率为 \(k\) 的直线,求其最大或最小纵截距。若能求出所有 \((x(l,r),y(l,r))\) 构成的凸包,就能在凸壳上二分求解了。
考虑求凸包的方法:分治,对于分支区间 \([l,r]\) 与其中点 \(p\),计算 \((x(l..p,p+1..r),y(l..p,p+1..r))\) 的贡献。分别求出后缀与前缀凸包,根据定义,求出左右凸包的 Minkowski 和即为当前层贡献,加入总点集,最后再求总点集的凸包即可。
复杂度 \(\mathcal O(n\log^2n+q\log n)\)。
\(\mathcal{Code}\)
/* Rainybunny */
#include <cstdio>
#include <vector>
#include <algorithm>
#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
typedef long long LL;
typedef long double LD;
inline int rint() {
int x = 0, f = 1, s = getchar();
for ( ; s < '0' || '9' < s; s = getchar() ) f = s == '-' ? -f : f;
for ( ; '0' <= s && s <= '9'; s = getchar() ) x = x * 10 + ( s ^ '0' );
return x * f;
}
template<typename Tp>
inline void wint( Tp x ) {
if ( x < 0 ) putchar( '-' ), x = -x;
if ( 9 < x ) wint( x / 10 );
putchar( x % 10 ^ '0' );
}
inline LL lmax( const LL a, const LL b ) { return a < b ? b : a; }
namespace PGP {
const LD EPS = 1e-9;
inline int dcmp( const LD a ) {
return -EPS < a && a < EPS ? 0 : a < 0 ? -1 : 1;
}
struct Point {
LL x, y;
Point(): x( 0 ), y( 0 ) {}
Point( const LL a, const LL b ): x( a ), y( b ) {}
inline Point operator + ( const Point& p ) const {
return { x + p.x, y + p.y };
}
inline Point operator - ( const Point& p ) const {
return { x - p.x, y - p.y };
}
inline int operator ^ ( const Point& p ) const {
return dcmp( LD( x ) * p.y - LD( y ) * p.x );
}
inline bool operator < ( const Point& p ) const {
return x != p.x ? x < p.x : y < p.y;
}
inline bool operator == ( const Point& p ) const {
return x == p.x && y == p.y;
}
};
typedef Point Vector;
typedef std::vector<Point> Convex;
inline Convex getConvex( std::vector<Point> vec ) {
static Convex ret; ret.clear();
std::sort( vec.begin(), vec.end() );
vec.resize( std::unique( vec.begin(), vec.end() ) - vec.begin() );
int n = int( vec.size() ), top = 0;
ret.resize( n << 1 );
rep ( i, 0, n - 1 ) {
for ( ; top > 1; --top ) {
if ( ( ( ret[top - 1] - ret[top - 2] )
^ ( vec[i] - ret[top - 2] ) ) > 0 ) break;
}
ret[top++] = vec[i];
}
for ( int tmp = top, i = n - 2; ~i; --i ) {
for ( ; top > tmp; --top ) {
if ( ( ( ret[top - 1] - ret[top - 2] )
^ ( vec[i] - ret[top - 2] ) ) > 0 ) break;
}
ret[top++] = vec[i];
}
top -= n > 1;
return ret.resize( top ), ret;
}
inline int findPole( const Convex& cvx ) {
int ret = -1, n = int( cvx.size() );
rep ( i, 0, n - 1 ) {
if ( !~ret || cvx[ret].y > cvx[i].y
|| ( cvx[ret].y == cvx[i].y && cvx[ret].x > cvx[i].x ) ) {
ret = i;
}
}
return ret;
}
inline void poleSort( Convex& cvx ) {
int pid = findPole( cvx ), n = int( cvx.size() );
pid = n - pid - 1;
std::reverse( cvx.begin(), cvx.end() );
std::reverse( cvx.begin(), cvx.begin() + pid + 1 );
std::reverse( cvx.begin() + pid + 1, cvx.end() );
}
inline Convex minkowskiSum( Convex A, Convex B ) {
static Convex ret; ret.clear();
poleSort( A ), poleSort( B );
int n = int( A.size() ), m = int( B.size() );
Point ap( A[0] ), bp( B[0] );
ret.push_back( ap + bp );
rep ( i, 0, n - 2 ) A[i] = A[i + 1] - A[i];
A[n - 1] = ap - A[n - 1];
rep ( i, 0, m - 2 ) B[i] = B[i + 1] - B[i];
B[m - 1] = bp - B[m - 1];
int i = 0, j = 0;
while ( i < n && j < m ) {
// 注意这里能 hack,应该计算极角来比较,否则无法正确处理共线向量。
ret.push_back( ret.back()
+ ( ( A[i] ^ B[j] ) > 0 ? A[i++] : B[j++] ) );
}
while ( i < n ) ret.push_back( ret.back() + A[i++] );
while ( j < m ) ret.push_back( ret.back() + B[j++] );
return ret;
}
} using namespace PGP;
const int MAXN = 1e5;
int n, q, rpos;
Point A[MAXN + 5];
Convex cvxA;
LL mnsec, mxsec;
inline void buildConvex( const int l, const int r ) {
if ( l == r ) return cvxA.push_back( A[l] );
int mid = l + r >> 1;
buildConvex( l, mid ), buildConvex( mid + 1, r );
static Convex cvxL, cvxR; cvxL.clear(), cvxR.clear();
Point cur;
per ( i, mid, l ) cvxL.push_back( cur = cur + A[i] );
cur = Point();
rep ( i, mid + 1, r ) cvxR.push_back( cur = cur + A[i] );
cvxL = minkowskiSum( getConvex( cvxL ), getConvex( cvxR ) );
for ( const auto& p: cvxL ) cvxA.push_back( p );
}
inline void init() {
buildConvex( 1, n ), cvxA = getConvex( cvxA );
#ifdef RYBY
puts( "+++ cvxA +++" );
for ( auto p: cvxA ) printf( "%lld %lld\n", p.x, p.y );
puts( "--- cvxA ---" );
#endif
if ( cvxA.size() == 1 ) rpos = 0;
else {
rpos = -1;
rep ( i, 1, cvxA.size() - 1 ) {
if ( cvxA[i].x <= cvxA[i - 1].x ) {
rpos = i - 1; break;
}
}
if ( !~rpos ) rpos = cvxA.size() - 1;
}
LL las = 0;
rep ( i, 1, n ) {
if ( ( las += A[i].x ) > mxsec ) mxsec = las;
if ( las < 0 ) las = 0;
}
las = 0;
rep ( i, 1, n ) {
if ( ( las += A[i].x ) < mnsec ) mnsec = las;
if ( las > 0 ) las = 0;
}
}
inline LL solve( const Point& P ) {
if ( !P.x ) return P.y > 0 ? -P.y * mnsec : -P.y * mxsec;
if ( cvxA.size() == 1 ) return P ^ cvxA[0];
Vector kp( P.x, P.y );
if ( kp.x < 0 ) kp.x = -kp.x, kp.y = -kp.y;
int s = int( cvxA.size() );
if ( P.x > 0 ) { // up convex.
int l = rpos, r = s;
while ( l < r ) {
int mid = l + r >> 1;
if ( ( ( cvxA[mid] - cvxA[( mid + 1 ) % s] ) ^ kp ) > 0 )
l = mid + 1;
else r = mid;
}
l %= s;
return P.x * cvxA[l].y - P.y * cvxA[l].x;
} else { // down convex.
int l = 0, r = rpos;
while ( l < r ) {
int mid = l + r >> 1;
if ( ( ( cvxA[( mid + 1 ) % s] - cvxA[mid] ) ^ kp ) > 0 )
l = mid + 1;
else r = mid;
}
l %= s;
return P.x * cvxA[l].y - P.y * cvxA[l].x;
}
}
int main() {
freopen( "area.in", "r", stdin );
freopen( "area.out", "w", stdout );
n = rint(), q = rint();
rep ( i, 1, n ) A[i].x = rint(), A[i].y = rint();
init();
for ( Point P; q--; ) {
P.x = rint(), P.y = rint();
wint( lmax( solve( P ), 0 ) ), putchar( '\n' );
}
return 0;
}
Solution -「多校联训」最大面积的更多相关文章
- Solution -「多校联训」排水系统
\(\mathcal{Description}\) Link. 在 NOIP 2020 A 的基础上,每条边赋权值 \(a_i\),随机恰好一条边断掉,第 \(i\) 条段的概率正比于 \(a ...
- Solution -「多校联训」I Love Random
\(\mathcal{Description}\) 给定排列 \(\{p_n\}\),可以在其上进行若干次操作,每次选取 \([l,r]\),把其中所有元素变为原区间最小值,求能够得到的所有不同序 ...
- Solution -「多校联训」签到题
\(\mathcal{Description}\) Link. 给定二分图 \(G=(X\cup Y,E)\),求对于边的一个染色 \(f:E\rightarrow\{1,2,\dots,c\ ...
- Solution -「多校联训」朝鲜时蔬
\(\mathcal{Description}\) Link. 破案了,朝鲜时蔬 = 超现实树!(指写得像那什么一样的题面. 对于整数集 \(X\),定义其 好子集 为满足 \(Y\sub ...
- Solution -「多校联训」消失的运算符
\(\mathcal{Description}\) Link. 给定长度为 \(n\) 的合法表达式序列 \(s\),其中数字仅有一位正数,运算符仅有 - 作为占位.求将其中恰好 \(k\) ...
- Solution -「多校联训」假人
\(\mathcal{Description}\) Link. 一种物品有 长度 和 权值 两种属性,现给定 \(n\) 组物品,第 \(i\) 组有 \(k_i\) 个,分别为 \((1,a ...
- Solution -「多校联训」古老的序列问题
\(\mathcal{Description}\) Link. 给定序列 \(\{a_n\}\),和 \(q\) 次形如 \([L,R]\) 的询问,每次回答 \[\sum_{[l,r]\su ...
- Solution -「多校联训」Sample
\(\mathcal{Description}\) Link (稍作简化:)对于变量 \(p_{1..n}\),满足 \(p_i\in[0,1],~\sum p_i=1\) 时,求 \(\ma ...
- Solution -「多校联训」光影交错
\(\mathcal{Description}\) Link. 一个游戏包含若干次卡牌抽取,每次以 \(p_l\) 的概率得到 \(+1\),\(p_d\) 的概率得到 \(-1\),否则得到 ...
随机推荐
- 细谈 Java 匿名内部类 【分别 使用 接口 和 抽象类实现】
1.前言 匿名内部类是什么东西? 没有名字的内部类就是匿名内部类. 什么场景使用? 匿名内部类适合创建那种只需要一次使用的类. 这是个很有用的东西,可想而知,如果不使用匿名内部类,哪些只需要使用一次的 ...
- Java的JDBC
第一个JDBC程序 创建测试数据库 CREATE DATABASE jdbcStudy CHARACTER SET utf8 COLLATE utf8_general_ci; USE jdbcStud ...
- Keil MDK STM32系列(五) 使用STM32CubeMX创建项目基础结构
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- C# - 逆变的具体应用场景
前言 早期在学习泛型的协变与逆变时,网上的文章讲解.例子算是能看懂,但关于逆变的具体应用场景这方面的知识,我并没有深刻的认识. 本文将在具体的场景下,从泛型接口设计的角度出发,逐步探讨逆变的作用,以及 ...
- [C# 学习]窗体间调用控件
一.方法1: 假如有两个窗体,Form_A和Form_B,每个窗体里都有一个按键,Button_A和Button_B,要实现单击Button_A显示窗体B,那么窗体A中Buttom_A的单击事件的程序 ...
- Cesium入门12 - Camera Modes - 相机模式
Cesium入门12 - Camera Modes - 相机模式 Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ ...
- Tomcat-给Tomcat添加第三方jar包
给动态web工程添加额外jar包 1,打开项目结构菜单操作界面,添加一个自己的类库 2,添加你当前类库需要的jar包 3,选择你添加的类库,给哪个模块使用 4,选择Artifacts选项,将类库添加到 ...
- 只要一行代码,实现五种 CSS 经典布局
常用的页面布局,其实就那么几个.下面我会介绍5个经典布局,只要掌握了它们,就能应对绝大多数常规页面. 这几个布局都是自适应的,自动适配桌面设备和移动设备.代码实现很简单,核心代码只有一行,有很大的学习 ...
- 阿里四面:你知道Spring AOP创建Proxy的过程吗?
Spring在程序运行期,就能帮助我们把切面中的代码织入Bean的方法内,让开发者能无感知地在容器对象方法前后随心添加相应处理逻辑,所以AOP其实就是个代理模式. 但凡是代理,由于代码不可直接阅读,也 ...
- Swift中数据类型
Swift类型的介绍 Swift中的数据类型也有:整型/浮点型/对象类型/结构体类型等等 先了解整型和浮点型 整型 有符号 Int8 : 有符号8位整型 Int16 : 有符号16位整型 Int32 ...