[省选联考 2025] 推箱子
我们先考虑 做法。按照 从小到大排序后,依次满足每个箱子的目标需求。若箱子移动的路线被其他箱子阻挡,此箱子会推着阻挡物前进。在此期间,任何一个箱子无法在规定时间内达到目标,将输出 No
,否则为 Yes
。
按照上述过程进行模拟,处理每个箱子时,若发现其前面 / 后面的箱子阻挡了其行进路线,将其直接移动到目标的前 / 后一格与上述描述也是等价的。若阻挡物也被阻挡了,进行同样过程的处理即可。
正解便是在此基础上进行的优化。我们发现,箱子推到一起后,会和其他箱子粘在一起运动许久。具体地,当一个箱子与后面的箱子粘连后,仅在后方箱子前往目标或自己前往目标时可能分离,且不会再次粘连,因此每两个箱子之间粘连 / 分开的次数是 的。
珂朵莉树 可以维护此过程 我怎么以前不知道这个东西是有名字的。我们维护一个 map
,键存放 段首元素的下标,值维护 段的长度 和 段首元素的位置( 的值)。由箱子相连可知,除段首元素,段内每个箱子的位置 都是前一个的位置 ,因此可以维护 数组。每次处理一个箱子时,先将该箱子单独分裂出来,然后维护出每个块前一个 / 后一个空着的位置 ,共其他段计算需要移动的距离。接着,处理路径中遇到的段,将其删除并记录,稍后进行合并操作,同时还要维护出新的 。等清理完所有障碍,移动到最终位置后,便可将合并出的新块添加回 map
中了。
按照上述分析,因此每两个箱子之间粘连 / 分开的次数是 的,算上 map
单次操作的复杂度为 ,最后的总复杂度为 ,且相比线段树做法,实现相当简单。
#include<bits/stdc++.h>
using namespace std;
using ui=unsigned int;
using uli=unsigned long long int;
istream& fin=cin;
ostream& fout=cout;
int main(void){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
ui c;size_t T;fin>>c>>T;
while (T--){
size_t n;fin>>n;
map<ui,pair<ui,ui>> a;
vector<ui> b(n);
vector<pair<uli,size_t>> t(n);
for (size_t i=0;i<n;++i){
ui x;
fin>>x>>b[i]>>t[i].first,t[i].second=i;
a.insert({i,{1,x}});
}
auto blkFst=[](decltype(a)::iterator x)->auto&{return x->first;};
auto blkPos=[](decltype(a)::iterator x)->auto&{return x->second.second;};
auto blkLen=[](decltype(a)::iterator x)->auto&{return x->second.first;};
sort(t.begin(),t.end());
uli d=0;
for (auto const& v:t){
size_t p=v.second;
auto it=prev(a.upper_bound(p));
if (blkFst(it)<p){
a.insert({p,{blkFst(it)+blkLen(it)-p,blkPos(it)+(p-blkFst(it))}});
it->second.first=p-blkFst(it);
++it;
}
if (blkLen(it)>1){
a.insert({p+1,{blkLen(it)-1,blkPos(it)+1}});
blkLen(it)=1;
}
if (blkPos(it)<b[p]){
ui e=b[p];
do{
d+=uli(e-blkPos(it))*blkLen(it);
e+=blkLen(it);
it=a.erase(it);
}while (it!=a.end()&&blkPos(it)<e);
a.insert({p,{e-b[p],b[p]}});
}else if (blkPos(it)>b[p]){
ui e=b[p]+1;
do{
d+=uli(blkPos(it)+blkLen(it)-e)*blkLen(it);
e-=blkLen(it);
it=a.erase(it);
--it;
}while (it!=a.end()&&blkPos(it)+blkLen(it)>e);
a.insert({p+1-(b[p]+1-e),{b[p]+1-e,e}});
}
if (d>v.first){fout<<"No\n";goto end1;}
}
fout<<"Yes\n";
end1:;
}
}