6167
前言
很厉害的题目!不涉及什么高深的算法,一些细节却并不好想。
思路
我们设
显然两个点
我们假设连边
则前者贡献是
考虑二分答案,判断答案是否
也即,
也即
我们设
我们不妨对每个
假设已经算出,我们就得到关于
于是考虑怎么算。直接对
考虑优化。
对于限制
限制
最后考虑第
也即,我们现在需要求
这个看上去只能
不过实际上由于本题性质,其可以做到
具体地,我们注意到随着
于是
拿一个单调栈维护一下。
如果你的
如果你的
于是剩下的栈里总形如
考虑建出栈之后,再解决栈内部的贡献。
这个直接双指针即可维护。
于是复杂度即为
最后由于要套一个二分答案,总复杂度
Code
代码跑得很快。
以下是核心代码。
uint n;
llt X[1000005],A[1000005],B[1000005];
llt MaxPreB[1000005],MaxSufA[1000005],c;
std::vector<std::pair<llt,llt> >S,T;
bol check(llt w)
{
llt x1=-1e18,x2=-1e18,x3=-1e18,x4=-1e18;
for(uint i=0;i<n;i++)
{
if(A[i]+MaxPreB[i]>w)_max(x3,MaxPreB[i]+A[i]),_max(x4,MaxPreB[i]+B[i]);
if(B[i]+MaxSufA[i]>w)_max(x1,MaxSufA[i]+A[i]);
}
for(auto s:T)if(s.first>w)_max(x2,s.second);
for(uint i=1,j=0;i<S.size();i++)if(S[0].second+S[i].first>w)
{
while(j+1<i&&S[j+1].second+S[i].first>w)j++;
_max(x2,S[j].first+S[i].second);
}
llt l_add=x1+c-w,r_add=w-x4-c,l_sub=x3+c-w,r_sub=w-x2-c;
_max(l_add,X[1]),_max(l_sub,0ll),_min(r_add,X[n-1]+X[n-2]),_min(r_sub,X[n-1]);
if(l_add>r_add||l_sub>r_sub)return false;
for(uint i=0,a=n,b=n,c=0,d=0;i<n;i++)
{
while(a&&X[i]+X[a-1]>=l_add)a--;
while(b&&X[i]+X[b-1]>r_add)b--;
while(c<n&&X[c]+l_sub<=X[i])c++;
while(d<n&&X[d]+r_sub<X[i])d++;
if(std::max(a,d)<std::min(b,c))return true;
}
return false;
}
int main()
{
#ifdef MYEE
freopen("QAQ.in","r",stdin);
freopen("QAQ.out","w",stdout);
#endif
scanf("%u%lld",&n,&c);
for(uint i=1;i<n;i++)scanf("%lld",X+i),X[i]+=X[i-1];
for(uint i=0;i<n;i++)scanf("%lld",A+i),B[i]=A[i]-X[i],A[i]+=X[i];
MaxPreB[0]=MaxSufA[0]=-1e18;
for(uint i=1;i<n;i++)_max(MaxPreB[i]=MaxPreB[i-1],B[i-1]);
for(uint i=n-1;i;i--)_max(MaxSufA[i-1]=MaxSufA[i],A[i]);
S={{A[0],B[0]}};
for(uint i=1;i<n;i++)
{
T.push_back({S.back().second+A[i],S.back().first+B[i]});
if(S.back().first>=A[i])continue;
while(S.size()&&S.back().second<=B[i])S.pop_back();
S.push_back({A[i],B[i]});
}
llt l=0,r=X[n-1]+2000000000;
while(l<r){llt mid=(l+r)>>1;if(check(mid))r=mid;else l=mid+1;}
printf("%lld\n",l);
return 0;
}