• 【JZOJ6217】【20190614】最大面积


    题意

    平面上有(n)个点(A_i)(q)次询问,每次给出一个点(P),求:

    [sum_{i=L}^{R} 2S_{ riangle OPA_i} ]

    最大值,其中$S_{ riangle_{ABC}} = frac{vec{AB} imesvec{AC} }{2} $为三角形的有向面积

    $1 le n le 10^5 , 1 le q le 10^6 $

    题解

    • 求出(n^2)个区间点和,求出他们构成的凸包

    • 对于一个询问向量((A,B)),最优的点就是((-A,-B))卡住的点(此时整个凸包在它左手边)

    • 对于所有询问可以旋转卡壳(O(q+n))完成

    • 考虑如何求(n^2)个区间点和构成的凸包

    • 对区间分治:考虑区间([l,r]) : 从(mid)向左做点后缀和,向右做点前缀和

    • 对两边分别求凸包做(minkowski)和就得到了跨越(mid)区间点和的凸包,分治下去

    • 这样得到的候选点的个数是(n log n)的,最后作一次总凸包

    • 时间复杂度(O(n log ^2 n + q))

      #include<bits/stdc++.h>
      #define il inline 
      #define rg register 
      #define ll long long  
      
      using namespace std;
      const int N=2000010;
      
      int n,m,tot,tp;ll ans[N];
      struct P{
      	ll x,y,z;
      	P(ll _x=0,ll _y=0,ll _z=0):x(_x),y(_y),z(_z){};
      	P operator +(const P&a)const{return P(x+a.x,y+a.y);}
      	P operator -(const P&a)const{return P(x-a.x,y-a.y);}
      	bool operator <(const P&a)const{return x==a.x?y<a.y:x<a.x;}
      	void rev(){x=-x,y=-y;}
      }p[N],q[N],L[N],R[N],S[N],st[N];
      ll crs(P a,P b){return a.x*b.y-a.y*b.x;}
      
      void chkmin(ll&x,ll y){if(x>y)x=y;}
      void chkmax(ll&x,ll y){if(x<y)x=y;}
      
      char gc(){
      	static char*p1,*p2,s[1000000];
      	if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
      	return(p1==p2)?EOF:*p1++;
      }
      int rd(){
      	int x=0,f=1;char c=gc();
      	while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
      	while(c>='0'&&c<='9'){x=x*10+c-'0';c=gc();}
      	return x*f;
      }
      char ps[1000000],*pp=ps;
      void flush(){fwrite(ps,1,pp-ps,stdout);pp=ps;}
      void push(char x){if(pp==ps+1000000)flush();*pp++=x;}
      void write(ll x){
      	static int sta[20],top;
      	if(x<0)push('-'),x=-x;
      	if(!x){push('0');push('
      ');return;}
      	while(x)sta[++top]=x%10,x/=10;
      	while(top)push(sta[top--]^'0');
      	push('
      ');
      }
      
      void convex(P*A,int&cnt){
      	if(cnt==1){A[2]=A[1];return;}
      	sort(A+1,A+cnt+1);
      	st[tp=1]=A[1];
      	for(int i=2;i<=cnt;++i){
      		while(tp>1 && crs(st[tp]-st[tp-1],A[i]-st[tp])<=0 )tp--;
      		st[++tp]=A[i];
      	}
      	int now=tp;
      	for(int i=cnt-1;i;--i){
      		while(tp>now && crs(st[tp]-st[tp-1],A[i]-st[tp])<=0 )tp--;
      		st[++tp]=A[i];
      	}
      	cnt=0;
      	for(int i=1;i<=tp;++i)if(!cnt||(st[i].x!=A[cnt].x||st[i].y!=A[cnt].y))A[++cnt]=st[i];
      	cnt--;
      }
      
      void minkow(P*A,int cnt1,P*B,int cnt2){
      	int j=1;
      	for(int i=1;i<=cnt1;++i){
      		S[++tot]=A[i]+B[j];
      		P now=A[i+1]-A[i];
      		while(j<=cnt2&&crs(B[j+1]-B[j],now)>=0)S[++tot]=A[i]+B[++j];
      	}
      	while(j<=cnt2)S[++tot]=A[1]+B[j++];
      }
      
      void solve(int l,int r){
      	if(l==r){S[++tot]=p[l];return;}
      	int mid=(l+r)>>1,cnt1=0,cnt2=0;
      	L[++cnt1]=R[++cnt2]=P(0,0);
      	for(int i=mid;i>=l;--i)++cnt1,L[cnt1]=L[cnt1-1]+p[i];
      	for(int i=mid+1;i<=r;++i)++cnt2,R[cnt2]=R[cnt2-1]+p[i];
      	convex(L,cnt1);convex(R,cnt2);
      	minkow(L,cnt1,R,cnt2);
      	solve(l,mid);solve(mid+1,r);
      }
      
      bool cmp(P a,P b){
      	return crs(a,b)>0;
      	//return atan2(a.y,a.x)<atan2(b.y,b.x);
      }
      void calc(){
      	sort(q+1,q+m+1,cmp);
      	int j=1,hd=1;while(!q[hd].x&&!q[hd].y)++hd;
      	//while(tot>1&&crs(q[hd],S[j%tot+1]-S[j])<=0)j=j%tot+1;
      	for(int i=1;i<=tot;++i)if(crs(q[hd],S[i]-S[j])<0)j=i;
      	for(int i=1;i<=m;++i){
      		if(!q[i].x&&!q[i].y)continue;
      		while(tot>1&&crs(q[i],S[j%tot+1]-S[j])<=0)j=j%tot+1;
      		ans[q[i].z]=-crs(q[i],S[j]);
      	}
      }
      //查询答案的时候注意细节, 存在(0,0).......
      int main(){
      	freopen("area.in","r",stdin);
      	freopen("area.out","w",stdout);
      	n=rd(),m=rd();
      	for(int i=1;i<=n;++i)p[i].x=rd(),p[i].y=rd();
      	int tmp=0;
      	for(int i=1;i<=m;++i){
      		q[++tmp].x=-rd(),q[tmp].y=-rd(),q[tmp].z=i;
      		if(!q[tmp].x&&!q[tmp].y)tmp--;
      	}
      	swap(tmp,m);
      	solve(1,n);
      	convex(S,tot);
      	calc();
      	for(int i=1;i<=tmp;++i)write(ans[i]);
      	return flush(),0;
      }
      //
      
  • 相关阅读:
    服务器做系统备份时失败
    PHPMailer中文乱码问题的解决方法
    html字符串分行显示
    Oracle中取某几个数的最大值最小值
    分布式事务之 Seata
    org.apache.dubbo 2.7.7 服务端处理请求及时间轮(失败重试)
    org.apache.dubbo 2.7.7 服务消费源码
    org.apache.dubbo 2.7.7 服务发布注册源码
    org.apache.dubbo 2.7.x 再聚首
    spring-cloud-gateway 服务网关
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/11074582.html
Copyright © 2020-2023  润新知