[集训队作业2018] 万圣节的积木(李超线段树)

传送门

设最底层为第1层,倒数第二层为第2层,以此类推。
发现若第 1 1 1 ~ i i i层构成的积木稳定,第 1 1 1 ~ j j j ( j > i j>i j>i)构成的积木也稳定,
那么第 i + 1 i+1 i+1 ~ j j j层构成的积木一定也是稳定的。

所以我们只要找到所有的 i i i满足第 1 1 1 ~ i i i层构成的积木稳定,答案就是相邻的 i i i之间的差的最大值。

然后一坨木板的加权重心是 ∑ i x i m i ∑ i m i \frac{\sum_{i}x_im_i}{\sum_{i}m_i} imiiximi,也就是 j + 1 … i j+1\dots i j+1i合法等价于
∑ j < k ≤ i ( R k + L k ) ( R k − L k ) 2 ∑ j < k ≤ i ( R k − L k ) = A i − A j B i − B j ∈ [ L j , R j ] \frac{\sum_{j<k\leq i}(R_k+L_k)(R_k-L_k)}{2\sum_{j<k\le i}(R_k-L_k)}=\frac{A_i-A_j}{B_i-B_j}\in[L_j,R_j] 2j<ki(RkLk)j<ki(Rk+Lk)(RkLk)=BiBjAiAj[Lj,Rj]

A i − A j B i − B j ≤ R j \frac{A_i-A_j}{B_i-B_j}\le R_j BiBjAiAjRj为例,其等价于 A i ≤ R j B i − R j B j + A j = F R j ( B i ) A_i\leq R_jB_i-R_jB_j+A_j=FR_j(B_i) AiRjBiRjBj+Aj=FRj(Bi),那么将 F R 1 ( x ) … F R i − 1 ( x ) FR_1(x)\dots FR_{i-1}(x) FR1(x)FRi1(x) B i B_i Bi 处的点值求出来取最小值和 A i A_i Ai比较一下即可,这个可以用李超线段树做。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=1e18;
const int N=1e5+10;
struct Line{
    
    
	ll k,b;
	Line(ll k=0,ll b=0):k(k),b(b){
    
    }
	ll y(ll x){
    
    return k*x+b;}
};
int n,L[N],R[N];
ll A[N],B[N],x[N];
bool ok[N];
namespace Seg1{
    
    
    Line t[N<<2];
    bool vis[N<<2];
    void modify(int u,int l,int r,Line v){
    
    
    	if(!vis[u]){
    
    
    		vis[u]=1;
    		t[u]=v;
    		return;
		}
		int mid=(l+r)>>1;
		if(t[u].y(x[mid])<v.y(x[mid])) swap(t[u],v);
		if(l==r) return;
		if(v.k<t[u].k) modify(u<<1,l,mid,v);
		else modify(u<<1|1,mid+1,r,v);
	}
    ll res;
    void query(int u,int l,int r,int p){
    
    
    	if(vis[u]) res=max(res,t[u].y(x[p]));
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	if(p<=mid) query(u<<1,l,mid,p);
    	else query(u<<1|1,mid+1,r,p);
	}
    ll query(int p){
    
    
        res=-inf;
        query(1,1,n,p);
        return res;
    }
}
namespace Seg2{
    
    
    Line t[N<<2];
    bool vis[N<<2];
    void modify(int u,int l,int r,Line v){
    
    
    	if(!vis[u]){
    
    
    		vis[u]=1;
    		t[u]=v;
    		return;
		}
		int mid=(l+r)>>1;
		if(t[u].y(x[mid])>v.y(x[mid])) swap(t[u],v);
		if(l==r) return;
		if(v.k>t[u].k) modify(u<<1,l,mid,v);
		else modify(u<<1|1,mid+1,r,v);
	}
    ll res;
    void query(int u,int l,int r,int p){
    
    
    	if(vis[u]) res=min(res,t[u].y(x[p]));
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	if(p<=mid) query(u<<1,l,mid,p);
    	else query(u<<1|1,mid+1,r,p);
	}
    ll query(int p){
    
    
        res=inf;
        query(1,1,n,p);
        return res;
    }
}
int main(){
    
    
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
    
    
        scanf("%d%d",&L[i],&R[i]);
        A[i]=A[i-1]+R[i]*R[i]-L[i]*L[i];
        B[i]=B[i-1]+2*(R[i]-L[i]);
    }
    for(int i=1;i<=n;i++) x[i]=B[i-1];
    for(int i=n;i>=1;i--){
    
    
        ok[i]=Seg1::query(i)<=A[i-1]&&Seg2::query(i)>=A[i-1];
        Seg1::modify(1,1,n,Line(R[i],A[i-1]-R[i]*B[i-1]));
        Seg2::modify(1,1,n,Line(L[i],A[i-1]-L[i]*B[i-1]));
    }
    int ans=0,lst=0;
    for(int i=1;i<=n;i++){
    
    
        if(ok[i]){
    
    
            ans=max(ans,i-lst);lst=i;
        }
    }
    printf("%d",ans);
}

参考文章:
https://blog.csdn.net/Mys_C_K/article/details/87931882

猜你喜欢

转载自blog.csdn.net/Emma2oo6/article/details/120732005