[省选联考 2025] 推箱子 题解
IvanZhang2009 · · 题解
大力宣传除了排序外线性做法!不用线段树等高级 ds!
首先注意到特殊性质
显然可以按
考虑
上面这个东西也可以理解为,我们从右往左依次移动,把
这个东西是很好优化到线性的。从小到大枚举
考虑如何快速求出上面说的一段前缀。箱子
插入一个点之后求出上一个和下一个点也可以单调栈预处理,就做到了线性处理一个段(除了按
考虑合并若干个段的限制。我们不妨认为一个点可以做多次操作。设限制序列中相邻两项
总时间复杂度除了排序外线性。非常好写。
考场代码:
#include<bits/stdc++.h>
#define MOD 998244353
#define int long long
#define REP(i,a,n) for(int i=a;i<(int)(n);++i)
#define pii pair<int,int>
#define pb push_back
#define all(v) v.begin(),v.end()
using namespace std;
int read(){
int res=0;char c=getchar();
while(c<48||c>57)c=getchar();
do res=(res<<1)+(res<<3)+(c^48),c=getchar();while(c>=48&&c<=57);
return res;
}
int qpow(int a,int b,int m=MOD){
int res=1;
while(b)res=b&1? res*a%MOD:res,a=a*a%MOD,b>>=1;
return res;
}
struct boxes{
int a,b,t;
};
int ID;
vector<pii>solve(vector<boxes>a){
int n=a.size();
if(a[0].a>a[0].b){
REP(i,0,n)a[i].a*=-1,a[i].b*=-1;
reverse(all(a));
}
vector<pii>st;
REP(i,0,n)st.pb({a[i].t,i});
sort(all(st));
vector<int>nxt(n);
int x=0;
REP(i,0,n){
while(x+1<n&&a[x+1].a-(x+1)<a[i].b-i)++x;
nxt[i]=x;
}
vector<int>s(n+1,0);
REP(i,0,n)s[i+1]=s[i]+a[i].a;
vector<int>f1(n,n),f2(n,-1);
stack<int>S;
REP(i,0,n){
while(!S.empty()&&a[S.top()].t>a[i].t)S.pop();
f1[i]=S.empty()? -1:S.top();
S.push(i);
}
while(!S.empty())S.pop();
for(int i=n-1;i>=0;--i){
while(!S.empty()&&a[S.top()].t>=a[i].t)S.pop();
f2[i]=S.empty()? n:S.top();
S.push(i);
}
vector<pii>ret;
int cur=0;
REP(_,0,st.size()){
int i=st[_].second,T=st[_].first;
nxt[i]=min(nxt[i],f2[i]-1);
cur+=(a[i].b*2+nxt[i]-i)*(nxt[i]-i+1)/2-s[nxt[i]+1]+s[i];
if(f1[i]!=-1){
int x=f1[i];
if(nxt[x]>=i){
cur-=(a[x].b*2+nxt[x]-x)*(nxt[x]-x+1)/2-s[nxt[x]+1]+s[x];
nxt[x]=i-1;
cur+=(a[x].b*2+nxt[x]-x)*(nxt[x]-x+1)/2-s[nxt[x]+1]+s[x];
}
}
ret.pb({T,cur});
}
return ret;
}
int n;
int a[200005],b[200005],t[200005];
void Main(){
n=read();
REP(i,0,n)a[i]=read(),b[i]=read(),t[i]=read();
vector<pii>R;
vector<int>v;
REP(i,0,n)if(a[i]!=b[i]){
int x=i;
while(x+1<n&&(a[x+1]<b[x+1])==(a[x]<b[x]))++x;
vector<boxes>T;
REP(j,i,x+1)T.pb({a[j],b[j],t[j]});
vector<pii>s=solve(T);
for(int j=s.size()-1;j;--j)s[j].second-=s[j-1].second;
for(auto j:s)R.pb(j);
i=x;
}
sort(all(R));
REP(i,1,R.size())R[i].second+=R[i-1].second;
REP(i,0,R.size())if(R[i].second>R[i].first){
cout<<"No\n";
return;
}
cout<<"Yes\n";
}
signed main(){
freopen("move.in","r",stdin);
freopen("move.out","w",stdout);
int tc=1;
ID=read();tc=read();
while(tc--)Main();
return 0;
}