ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

6217. 【NOI2019模拟2019.6.14】最大面积

2021-05-07 08:01:25  阅读:167  来源: 互联网

标签:2019.6 back NOI2019 6217 ans push 凸包 ll DOT


有一堆向量\(A_i\),多次询问向量\(P\),查\(\max_{L\le R}P\times \sum_{i=L}^R A_i\)。

\(n\le 10^5\)


设向量\(P=(A,B)\),区间和为\((X,Y)\)。需要最大化\(F=AY-BX\)。于是\(Y=\frac{B}{A}X+\frac{F}{A}\)。以\(A>0\)为例,相当于在\((X,Y)\)引一条斜率\(\frac{B}{A}\)的直线,求所有这样的\((X,Y)\)引出的直线的最大截距。

于是答案一定在所有\((X,Y)\)组成的凸包上。如果能求出这个凸包,就可以直接在上凸壳上二分在\(O(\lg)\)的时间内得到答案。

以下是构建这个凸包的方式:分治构造,求出\([L,mid],[mid+1,R]\)内的凸包,以及跨过中点的。对于跨过中点的,对左区间做后缀和,对右区间做前缀和,两者闵科夫斯基和。然后把得到的这三个凸包合并起来。

因为一个分治区间最多贡献区间长度的点数,总点数不超过区间总长,即\(O(n\lg n)\)。因为中间还需要归并,时间至少\(O(n\lg^2n)\)。

(诶所以我的实现方式是\(O(n\lg^3 n)\)?)


第一次写凸包(平常只是维护个凸壳)+第一次写闵科夫斯基和。

其实凸包可以直接分别维护上凸壳和下凸壳,应该更好写,也方便优化(在已经排好序的情况下,凸包合并应该可以线性做)

这次用极角排序的方式写凸包,有点细节。

求凸包和闵科夫斯基和的时候都需要找到最左端(坐标相同就最下端)的点作为基准点,从它开始跑,因为这样保证了这个点一定在凸包上。

然后凸包合并的时候我重新求了一次凸包,所以时间多了一个\(O(\lg)\)。

using namespace std;
#include <bits/stdc++.h>
#define N 100005
#define ll long long
#define db long double
int n,Q;
struct DOT{
	ll x,y;
	DOT(ll _x=0,ll _y=0){x=_x,y=_y;}
	db len2(){return (db)x*x+(db)y*y;}
} d[N];
bool operator<(DOT a,DOT b){return a.x<b.x || a.x==b.x && a.y<b.y;}
DOT operator+(DOT a,DOT b){return (DOT){a.x+b.x,a.y+b.y};}
DOT operator-(DOT a,DOT b){return (DOT){a.x-b.x,a.y-b.y};}
db cro(DOT a,DOT b){return (db)a.x*b.y-(db)a.y*b.x;}
vector<DOT> q[N*4],u,v;
vector<DOT> qa;
bool cmparc(DOT a,DOT b){return cro(a,b)>0 || cro(a,b)==0 && a.len2()<b.len2();}
void getcon(vector<DOT> &w){
	DOT O=w[0];
	for (int i=1;i<w.size();++i)
		O=min(O,w[i]);
	qa.clear();
	for (int i=0;i<w.size();++i)
		if (w[i].x!=O.x || w[i].y!=O.y)
			qa.push_back(w[i]-O);
	sort(qa.begin(),qa.end(),cmparc);
	static DOT st[N*20];
	int tp;
	st[tp=1]=DOT(0,0);
	for (int i=0;i<qa.size();++i){
		while (tp>1 && cro(st[tp]-st[tp-1],qa[i]-st[tp-1])<=0)
			--tp;
		st[++tp]=qa[i];
	}
	while (tp>1 && cro(st[tp]-st[tp-1],DOT(0,0)-st[tp-1])<0)
		--tp;
	w.clear();
	for (int i=1;i<=tp;++i)
		w.push_back(st[i]+O);
}
void getsum(vector<DOT> &w){
	DOT O=u[0]+v[0];
	u.push_back(u[0]);
	v.push_back(v[0]);
	w.clear();
	w.push_back(O);
	int i=0,j=0;
	while (i<u.size()-1 || j<v.size()-1)
		if (i<u.size()-1 && (j==v.size()-1 || cro(u[i+1]-u[i],v[j+1]-v[j])>0))
			w.push_back(O=O+u[i+1]-u[i]),i++;
		else
			w.push_back(O=O+v[j+1]-v[j]),j++;
	w.pop_back();
}
void merge(vector<DOT> &a,vector<DOT> &b){
	for (int i=0;i<b.size();++i)
		a.push_back(b[i]);
	b.clear();
}
void divide(int k,int l,int r){
	if (l==r){
		q[k].push_back(d[l]);
		return;
	}
	int mid=l+r>>1;
	divide(k<<1,l,mid);
	divide(k<<1|1,mid+1,r);
	u.clear(),v.clear();
	DOT s(0,0);
	for (int i=mid;i>=l;--i)
		s=s+d[i],u.push_back(s);
	s=DOT(0,0);
	for (int i=mid+1;i<=r;++i)
		s=s+d[i],v.push_back(s);
	getcon(u);
	getcon(v);
	getsum(q[k]);
	merge(q[k],q[k<<1]);
	merge(q[k],q[k<<1|1]);
	getcon(q[k]);
}
vector<DOT> f,g;
ll ask(vector<DOT> &h,DOT p){
	ll ans=0;
	for (int i=0;i<h.size();++i){
		ans=max(ans,(ll)cro(p,h[i]));
	}
	return ans;
	int l=0,r=(int)h.size()-2,res=h.size()-1;
	while (l<=r){
		int mid=l+r>>1;
		if (cro(p,h[mid+1]-h[mid])<=0)
			r=(res=mid)-1;
		else
			l=mid+1;
	}
	return cro(p,h[res]);
}
int main(){
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
//	freopen("area.in","r",stdin);
//	freopen("area.out","w",stdout);
	scanf("%d%d",&n,&Q);
	for (int i=1;i<=n;++i)
		scanf("%lld%lld",&d[i].x,&d[i].y);
	divide(1,1,n);
	DOT lef=q[1][0],rig=q[1][0];
	int pos=0;
	for (int i=1;i<q[1].size();++i)
		if (rig<q[1][i])
			rig=q[1][i],pos=i;
	for (int i=0;i<=pos;++i) f.push_back(DOT(q[1][i].x,-q[1][i].y));
	g.push_back(lef);
	for (int i=q[1].size()-1;i>=pos;--i) g.push_back(q[1][i]);
	while (Q--){
		ll A,B;
		scanf("%lld%lld",&A,&B);
		ll ans=0;
		if (A==0){
			if (B==0)
				ans=0;
			else
				ans=max(-B*lef.x,-B*rig.x);
		}
		else if (A>0)
			ans=ask(g,DOT(A,B));
		else
			ans=ask(f,DOT(-A,B));
		printf("%lld\n",ans);
	}
	return 0;
}

标签:2019.6,back,NOI2019,6217,ans,push,凸包,ll,DOT
来源: https://www.cnblogs.com/jz-597/p/14737604.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有