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

FFTotoro
龙猫搬运于
2025-08-24 22:57:54,当前版本为作者最后更新于2024-05-12 21:50:03,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
观察性质题。下称“投喂 饲料”为“执行 操作”, 饲料同理。
考虑暴力怎么做。显然一个 操作等价于令某个 ,而最后能通过 操作完成的序列 必然单调不降(因为每次可以给一个后缀 ,所以前面的数永远不会大于后面的)。
考虑另一种“暴力”,就是将询问离线,按 从小到大排序然后扫一遍过去,每次扫到一个新的 ,如果 就暴力往前更新,直到满足条件。
上面的这种暴力看起来很能找性质进行优化。观察到如果我们更新过了一对相邻的数,那么接下来不管怎么更新,它们的差不变!证明:每次更新都是对一个 进行 ,考虑 的剩余系即可。于是考虑用一个栈维护还没有更新的位置(因为如果右边的不用更新左边的也不用更新),所以每次从栈顶开始暴力往下查有没有冲突,如果有直接更新中间一段的值,然后把栈顶删掉……均摊一下这种操作最多做 次。区间加区间和可以用线段树维护。于是做完了,时间复杂度 。
放代码:
#include<bits/stdc++.h> #define int long long using namespace std; typedef pair<int,int> pii; inline int ceil_div(int x,int y){ return x/y+!!(x%y); } class segtree{ private: int n; vector<pii> B; vector<int> S,T; public: inline void pushup(int u){ S[u]=S[u<<1]+S[u<<1|1]; } inline int size(int u){ return B[u].second-B[u].first+1; } inline void pushdown(int u){ S[u<<1]+=T[u]*size(u<<1),S[u<<1|1]+=T[u]*size(u<<1|1); T[u<<1]+=T[u],T[u<<1|1]+=T[u],T[u]=0; } segtree(int N){ n=N,B.resize(n<<2),S.resize(n<<2),T.resize(N<<2); function<void(int,int,int)> build=[&](int u,int l,int r){ if(B[u]=make_pair(l,r);l==r)return; int m=l+r>>1; build(u<<1,l,m),build(u<<1|1,m+1,r); }; build(1,0,n-1); } inline void update(int u,int l,int r,int x){ if(B[u].first>r||B[u].second<l)return; if(l<=B[u].first&&B[u].second<=r){ T[u]+=x,S[u]+=x*size(u); return; } pushdown(u); update(u<<1,l,r,x),update(u<<1|1,l,r,x); pushup(u); } inline int query(int u,int l,int r){ if(B[u].first>r||B[u].second<l)return 0; if(l<=B[u].first&&B[u].second<=r)return S[u]; pushdown(u); return query(u<<1,l,r)+query(u<<1|1,l,r); } }; // 线段树 main(){ ios::sync_with_stdio(false); int n,d; cin>>n>>d; vector<int> c(n); for(auto &i:c)cin>>i; int q; cin>>q; vector<vector<pii> > Q(n); vector<int> R(q); for(int i=0;i<q;i++){ int l,r; cin>>l>>r; Q[r-1].emplace_back(l-1,i); } // 把询问离线下来 segtree t(n); auto get=[&](int p){return c[p]-t.query(1,p,p)*d;}; stack<int> s; for(int i=0;i<n;i++){ int r=i; while(!s.empty()){ int l=s.top(),x=get(r-1),y=get(r); if(x<=y)break; t.update(1,l,r-1,ceil_div(x-y,d)); r=l,s.pop(); } // 弹栈顶,均摊 N 次 s.emplace(r); for(auto [l,w]:Q[i]) R[w]=(get(l)<0?-1:t.query(1,l,i)); } for(int i:R)cout<<i<<'\n'; return 0; }
- 1
信息
- ID
- 10239
- 时间
- 2000ms
- 内存
- 1024MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者