CF671E Organizing a Race(线段树维护前缀最值+贪心)
CF671E Organizing a Race
分别设
则从
首先考虑从
下面就只需要让
考虑对于每个
那么,对于每个固定的
现在问题转化为了维护
对于查询操作,一般情况下可以直接线段树上二分,但这里略有不同。考虑一个
-
bmi_{ls}<x$ 时,$x$ 不影响右区间,那么 $ans_{ro}\le k$ 时向右子树递归,否则向左子树递归,时间复杂度为 $O(\log n) -
bmi_{ls}\ge x$ 时,左子树完全被 $x$ 控制了。先向右子树递归,如果有合法的直接 return;否则在左子树中查$a_i-x\le k$ 的最大的 $i$ ,移项得 $a_i\le k+x$,这就是一个经典的线段树上二分了。因为最多进行 $O(\log n)$ 次线段树上二分,总复杂度为$O(\log^2n)
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
using namespace std;
typedef long long ll;
namespace FGF
{
const int N=1e5+5;
const ll INF=0x3f3f3f3f3f3f3f3f;
int g[N],w[N],n,m,nxt[N],st[N],ans=1,tp;
struct tree{
ll ans,ami,bmi,ta;
}t[N<<2];
ll pre[N],suf[N];
vector<int> G[N];
void add(int ro,ll x){t[ro].bmi+=x,t[ro].ans-=x,t[ro].ta+=x;}
void pushdown(int ro){if(t[ro].ta)add(ro<<1,t[ro].ta),add(ro<<1|1,t[ro].ta),t[ro].ta=0;}
ll pushup(int ro,int l,int r,ll p)
{
if(l==r)return t[ro].ami-p;
pushdown(ro);
return t[ro<<1].bmi<p?min(pushup(ro<<1,l,mid,p),t[ro].ans):min(t[ro<<1].ami-p,pushup(ro<<1|1,mid+1,r,p));
}
void build(int ro,int l,int r)
{
if(l==r){t[ro].ami=t[ro].bmi=suf[l];return;}
build(ro<<1,l,mid),build(ro<<1|1,mid+1,r);
t[ro].ans=pushup(ro<<1|1,mid+1,r,t[ro<<1].bmi);
t[ro].ami=min(t[ro<<1].ami,t[ro<<1|1].ami),t[ro].bmi=min(t[ro<<1].bmi,t[ro<<1|1].bmi);
}
void updat(int ro,int l,int r,int L,int R,ll x)
{
if(L<=l&&r<=R)return add(ro,x);
pushdown(ro);
if(L<=mid)updat(ro<<1,l,mid,L,R,x);
if(R>mid)updat(ro<<1|1,mid+1,r,L,R,x);
t[ro].bmi=min(t[ro<<1].bmi,t[ro<<1|1].bmi);
t[ro].ans=pushup(ro<<1|1,mid+1,r,t[ro<<1].bmi);
}
int query2(int ro,int l,int r,ll x)
{
if(l==r)return l;
return t[ro<<1|1].ami<=x?query2(ro<<1|1,mid+1,r,x):query2(ro<<1,l,mid,x);
}
int query(int ro,int l,int r,ll &x)
{
if(l==r)
{
int tmp=t[ro].ami-x<=m?l:0;
x=min(x,t[ro].bmi);
return tmp;
}
pushdown(ro);
if(x>t[ro<<1].bmi)
{
if(t[ro].ans<=m)return query(ro<<1|1,mid+1,r,x=t[ro<<1].bmi);
int tmp=query(ro<<1,l,mid,x);
x=min(x,t[ro].bmi);
return tmp;
}
else
{
int tmp=(t[ro<<1].ami<=m+x?query2(ro<<1,l,mid,m+x):0);
return max(tmp,query(ro<<1|1,mid+1,r,x));
}
}
void dfs(int u)
{
if(nxt[u]<=n)updat(1,1,n,nxt[u]-1,n,pre[u]-pre[nxt[u]]);
if(u<=n)
{
int l=2,r=tp,s=1;ll x=INF;
while(l<=r)pre[st[mid]]-pre[u]>m?(s=mid,l=mid+1):r=mid-1;
if(u>1)updat(1,1,n,1,u-1,INF);
updat(1,1,n,st[s]-1,n,-INF);
ans=max(ans,query(1,1,n,x)-u+1);
if(u>1)updat(1,1,n,1,u-1,-INF);
updat(1,1,n,st[s]-1,n,INF);
}
st[++tp]=u;
for(auto v:G[u])dfs(v);
if(nxt[u]<=n)updat(1,1,n,nxt[u]-1,n,pre[nxt[u]]-pre[u]);
tp--;
}
void work()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
scanf("%d",&w[i]);
for(int i=1;i<=n;i++)
scanf("%d",&g[i]);
for(int i=2;i<=n;i++)
pre[i]=pre[i-1]+w[i-1]-g[i-1],suf[i]=suf[i-1]+w[i-1]-g[i];
for(int i=1;i<=n;i++)
nxt[i]=n+1;
for(int i=n;i;i--)
{
while(tp&&pre[st[tp]]<=pre[i])tp--;
if(tp)nxt[i]=st[tp];
st[++tp]=i;
G[nxt[i]].push_back(i);
}
build(1,1,n);
tp=0;
dfs(n+1);
printf("%d\n",ans);
}
}
int main()
{
FGF::work();
return 0;
}