题解:P15292 [MCO 2023] Two Pointers (hard version)
lailai0916 · · 题解
题意简述
Alice 和 Bob 位于数轴上的不同位置。
现在依次发生
解题思路
处理完第
设此时的最小代价为
- 原固定者从
t_{i-1} 移动到t_i ,另一人仍在p ; - 原本位于
p 的人移动到t_i ,原固定者留在t_{i-1} 。
第一种方式会让每个已有状态同时增加:
第二种方式只会得到一个另一人位于
若直接维护
执行第一种转移时,只需令
考虑如何求第二种转移。令
所有可能出现的位置只有
这样,一次前缀查询和一次后缀查询即可求出上式。由于同一位置可能多次产生状态,单点修改应对原值取最小值。
设查询结果为
处理第一个事件时有两种初始状态:
此时
下面说明状态转移的正确性。
假设处理完事件
离散化和每次线段树操作的时间复杂度均为
参考代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=300005;
const int M=1048580;
const ll inf=0x3f3f3f3f3f3f3f3f;
int n,m,s;
ll a,b,t[N],f[M][2];
vector<ll> v;
int get(ll x)
{
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void add(ll x,ll y)
{
int p=get(x)+s-1;
f[p][0]=min(f[p][0],y-x);
f[p][1]=min(f[p][1],y+x);
for(p>>=1;p;p>>=1)
{
f[p][0]=min(f[p*2][0],f[p*2+1][0]);
f[p][1]=min(f[p*2][1],f[p*2+1][1]);
}
}
ll ask(int l,int r,int k)
{
ll res=inf;
for(l+=s-1,r+=s-1;l<=r;l>>=1,r>>=1)
{
if(l&1)res=min(res,f[l++][k]);
if(!(r&1))res=min(res,f[r--][k]);
}
return res;
}
ll query(ll x)
{
int p=get(x);
return min(ask(1,p,0)+x,ask(p,m,1)-x);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>n>>a>>b;
v.push_back(a);
v.push_back(b);
for(int i=1;i<=n;i++)
{
cin>>t[i];
v.push_back(t[i]);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
m=v.size();
for(s=1;s<m;s*=2);
for(int i=1;i<s*2;i++)
{
f[i][0]=inf;
f[i][1]=inf;
}
ll x=abs(a-t[1]);
add(b,x);
ll y=abs(b-t[1]);
add(a,y);
ll delta=0;
ll mn=min(x,y);
for(int i=2;i<=n;i++)
{
ll res=query(t[i]);
ll d=abs(t[i]-t[i-1]);
delta+=d;
res-=d;
add(t[i-1],res);
mn=min(mn,res);
}
cout<<delta+mn<<'\n';
return 0;
}