1 条题解
-
0
自动搬运
来自洛谷,原作者为

myee
与其诺诺以顺,不若谔谔以昌 | AFO搬运于
2025-08-24 22:18:07,当前版本为作者最后更新于2023-06-14 21:32:24,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
前言
很厉害的题目!不涉及什么高深的算法,一些细节却并不好想。
思路
我们设 。
显然两个点 要么走树上路径,要么走跨越该边的路径。
我们假设连边 ,满足 。
则前者贡献是 ,后者贡献是 。
考虑二分答案,判断答案是否 。
也即,
$$\forall u<v,d_u+d_v+\min\{x_v-x_u,|x_u-x_s|+|x_v-x_t|+c\}\le w $$也即
$$\forall u<v,(d_u-x_u)+(d_v+x_v)\le w\lor\begin{cases}(d_u+x_u)+(d_v+x_v)\le w+x_s+x_t-c\\(d_u+x_u)+(d_v-x_v)\le w+x_s-x_t-c\\(d_u-x_u)+(d_v+x_v)\le w-x_s+x_t-c\\(d_u-x_u)+(d_v-x_v)\le w-x_s-x_t-c\end{cases} $$我们设 ,那么合法等价于
$$\forall u<v,B_u+A_v\le w\lor\begin{cases}A_u+A_v\le w+x_s+x_t-c\\A_u+B_v\le w+x_s-x_t-c\\B_u+A_v\le w-x_s+x_t-c\\B_u+B_v\le w-x_s-x_t-c\end{cases} $$我们不妨对每个 算出后面四条限制的左式的最大值。
假设已经算出,我们就得到关于 和 的四条方程,也就得到 的上下界,枚举下 ,可以顺带对 的区间拿四个指针维护一下做到 。
于是考虑怎么算。直接对 一维分治是单轮 的,总复杂度 ,较难通过。
考虑优化。
对于限制 ,考虑直接枚举 。那么我们就是要得到前缀中每个 的 ,直接维护前缀中最大 ,然后 check 其是否 即可。
限制 可以通过枚举 类似地实现。
最后考虑第 条限制怎么求。
也即,我们现在需要求
这个看上去只能 计算。
不过实际上由于本题性质,其可以做到 !
具体地,我们注意到随着 的增长,必有 变大。
于是 对只可能出现三种情况(把等于视作边界情况):
- 增, 增。
- 增, 减。
- 减, 减。
拿一个单调栈维护一下。
如果你的 均比上一个小,直接被暴打,因此可以当作不存在。顺带计算一下和上一项之间的贡献即可。
如果你的 均比上一个大,直接暴打那个数,不妨在把上一个数弹栈的同时计算一下弹栈的两个数之间的贡献。
于是剩下的栈里总形如 单调增 单调减。
考虑建出栈之后,再解决栈内部的贡献。
这个直接双指针即可维护。
于是复杂度即为 。
最后由于要套一个二分答案,总复杂度 。
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; }
- 1
信息
- ID
- 5175
- 时间
- 2000ms
- 内存
- 250MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者