[ARC073F]Many Moves

Posted by Dispwnl on April 24, 2019

题目

题目大意

在一行中有$n$个格子,从左往右编号为$1$到$n$。

有$2$颗棋子,一开始分别位于位置$A$和$B$。按顺序给出$Q$个要求,每个要求是如下形式:

  • 给出一个位置$x_i$,要求将两个棋子中任意一个移动到位置$x_i$。

将一颗棋子移动一格需要花费$1$秒,就是说将棋子从$X$位置移动到$Y$位置需要花费$\vert X-Y\vert $秒。

为了回答要求,你只能移动棋子,并且同一时刻只能移动一颗棋子。要求的顺序是不可更改的。在同一时间允许两颗棋子在同一个格子内。

Sample Input 1

8 3 1 8
3 5 1

Sample Output 1

7

Sample Input 2

9 2 1 9
5 1

Sample Output 2

4

Sample Input 3

9 2 1 9
5 9

Sample Output 3

4

Sample Input 4

11 16 8 1
1 1 5 1 11 4 5 2 5 3 3 3 5 5 6 7

Sample Output 4

21

题解

看到有两个棋子移动就想到设状态$f_{i,j}$表示第$i$次移动不动的棋子在$j$位置的最小代价,则有转移

$f_{i,j}=f_{i-1,j}+\vert x_i-x_{i-1} \vert,f_{i,x_{i-1}}=\min(f_{i-1,j}+\vert j-x_i\vert)$

线段树维护即可

取值用int,爆负两行泪

代码

# include<iostream>
# include<cstring>
# include<cstdlib>
# include<cstdio>
# include<algorithm>
# define tl (k<<1)
# define tr (k<<1|1)
# define mid (l+r>>1)
# define LL long long
using namespace std;
const int MAX=2e5+5;
const LL inf=1e14;
struct p{
	LL x,xup,xdn,tags;
	p(LL X=0,LL XU=0,LL XD=0,LL TAG=0) {x=X,xup=XU,xdn=XD,tags=TAG;}
}s[MAX<<2];
int n,Q,A,B;
int X[MAX];
int read()
{
	int x(0);
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar());
	for(;isdigit(ch);x=x*10+ch-48,ch=getchar());
	return x;
}
p min(p a,p b) {return p(min(a.x,b.x),min(a.xup,b.xup),min(a.xdn,b.xdn));}
void pus(int k) {s[k]=min(s[tl],s[tr]);}
void Add(int k,LL d) {s[k].tags+=d,s[k].x+=d,s[k].xup+=d,s[k].xdn+=d;}
void down(int k) {if(s[k].tags) Add(tl,s[k].tags),Add(tr,s[k].tags),s[k].tags=0;}
void change(int l,int r,int k,int x,LL d)
{
	if(l==r) {d=min(d,inf),s[k].x=d,s[k].xup=d+l,s[k].xdn=d-l;return;}
	down(k);
	if(x<=mid) change(l,mid,tl,x,d);
	else change(mid+1,r,tr,x,d);
	pus(k);
}
void change(int l,int r,int k,int L,int R,int d)
{
	if(r<L||R<l) return;
	if(l>=L&&r<=R) return void(Add(k,d));
	down(k),change(l,mid,tl,L,R,d),change(mid+1,r,tr,L,R,d),pus(k);
}
LL ask(int l,int r,int k,int L,int R)
{
	if(r<L||R<l) return inf;
	if(l>=L&&r<=R) return s[k].x;
	return down(k),min(ask(l,mid,tl,L,R),ask(mid+1,r,tr,L,R));
}
LL ask_up(int l,int r,int k,int L,int R)
{
	if(r<L||R<l) return inf;
	if(l>=L&&r<=R) return s[k].xup;
	return down(k),min(ask_up(l,mid,tl,L,R),ask_up(mid+1,r,tr,L,R));
}
LL ask_down(int l,int r,int k,int L,int R)
{
	if(r<L||R<l) return inf;
	if(l>=L&&r<=R) return s[k].xdn;
	return down(k),min(ask_down(l,mid,tl,L,R),ask_down(mid+1,r,tr,L,R));
}
void build(int l=1,int r=n,int k=1)
{
	s[k]=p(inf,inf,inf);
	if(l==r) return;
	build(l,mid,tl),build(mid+1,r,tr);
}
int main()
{
	n=read(),Q=read(),A=read(),B=read(),build();
	for(int i=1;i<=Q;++i)
	  {
	  	X[i]=read();
	  	if(i==1) change(1,n,1,A,abs(B-X[i])),change(1,n,1,B,abs(A-X[i]));
		else
		{
			LL Lv=ask_down(1,n,1,1,X[i])+X[i],Rv=ask_up(1,n,1,X[i]+1,n)-X[i],Xv=ask(1,n,1,X[i-1],X[i-1]);
			change(1,n,1,X[i-1],min(Xv+abs(X[i]-X[i-1]),min(Lv,Rv))),change(1,n,1,1,X[i-1]-1,abs(X[i]-X[i-1])),change(1,n,1,X[i-1]+1,n,abs(X[i]-X[i-1]));
		}
	  }
	LL ans=1e18;
	for(int i=1;i<=n;++i)
	  ans=min(ans,ask(1,n,1,i,i));
	return printf("%lld",ans),0;
}