题解:(假设最底层的是1)不难发现每次把某个
放上去,必须要有
是合法的,那么
都是合法的。
然后一坨木板的加权重心是
,也就是
合法等价于
以
为例,其等价于
,那么将
在
处的点值求出来取最小值和
比较一下即可,这个可以用李超线段树做。
最后答案显然就是相邻一对合法的差的最大值。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const lint INF=LLONG_MAX;const int N=100010;
int L[N],R[N];lint A[N];int B[N];
struct Line{
lint k,b;Line(lint _k=0,lint _b=0) { k=_k,b=_b; }
inline lint operator() (lint x) { return k*x+b; }
};
struct segment{
Line f;segment *ch[2];
}*rtL,*rtR;
inline lint query(segment* &rt,int l,int r,int p)
{
if(rt==NULL) return INF;lint v=rt->f(p);
if(l==r) return v;int mid=l+(r-l)/2;
if(p<=mid) return min(v,query(rt->ch[0],l,mid,p));
else return min(v,query(rt->ch[1],mid+1,r,p));
}
inline int update(segment* &rt,int l,int r,Line f)
{
if(rt==NULL) return rt=new segment,rt->ch[0]=rt->ch[1]=NULL,rt->f=f,0;
int mid=l+(r-l)/2;if(rt->f(l)>f(l)) swap(rt->f,f);if(rt->f(r)<=f(r)) return 0;
if(rt->f(mid)<=f(mid)) return update(rt->ch[1],mid+1,r,f);
else return swap(rt->f,f),update(rt->ch[0],l,mid,f);return 0;
}
int main()
{
int n=inn(),las=0,ans=0;rtL=NULL,rtR=NULL;
rep(i,1,n) L[i]=inn(),R[i]=inn();
reverse(L+1,L+n+1),reverse(R+1,R+n+1);
rep(i,1,n) A[i]=A[i-1]+R[i]*R[i]-L[i]*L[i];
rep(i,1,n) B[i]=B[i-1]+2*(R[i]-L[i]);
rep(i,1,n)
{
lint fL=query(rtL,1,B[n],B[i]),fR=query(rtR,1,B[n],B[i]);
if(A[i]<=fR&&-A[i]<=fL) ans=max(ans,i-las),las=i;
update(rtL,1,B[n],Line(-L[i],(lint)L[i]*B[i]-A[i]));
update(rtR,1,B[n],Line(R[i],-(lint)R[i]*B[i]+A[i]));
}
return !printf("%d\n",max(ans,n-las));
}