题解 [ABC334F] Christmas Present 2

【洛谷博客】

有一定难度的 ABC F。

题意

翻译很清楚。

标签:动态规划、线段树。

分析

\(f_i\) 表示到第 \(i\) 个点后回到原点(即 \(0\) 号)的最小距离。

在第 \(i\) 个点时,第 \(i-1\) 个点才回到原点,需要重新出发,即加上 \(0\) 号点到 \(i\) 号点的距离;而对于 \(\forall j \in[i-k,i-1)\),这些点已经出发到了第 \(i-1\) 个点,即加上 \(i-1\) 号点到 \(i\) 号点的距离。

区间加和,区间查询,这个直接用线段树维护即可。

时间复杂度 \(O(n \log n)\)

代码

//the code is from chenjh
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define MAXN 200002
using namespace std;
typedef long long LL;
typedef unsigned int ui;
using cu=const unsigned int;
int n,k;
int X[MAXN],Y[MAXN];
double dis(const int X1,const int Y1,const int X2,const int Y2){return sqrt((LL)(X1-X2)*(X1-X2)+(LL)(Y1-Y2)*(Y1-Y2));}//求两个坐标之间的距离。
#define lson (rt<<1)
#define rson (rt<<1|1)
double mn[MAXN<<2],lazy[MAXN<<2];//线段树维护最小值。
void pd(cu rt,cu l,cu r){
	mn[lson]+=lazy[rt],lazy[lson]+=lazy[rt];
	mn[rson]+=lazy[rt],lazy[rson]+=lazy[rt];
	lazy[rt]=0;
}
void update(cu rt,cu l,cu r,cu L,cu R,const double&val){
	if(L<=l && r<=R){mn[rt]+=val,lazy[rt]+=val;return;}
	pd(rt,l,r);
	ui mid=(l+r)>>1;
	if(L<=mid) update(lson,l,mid,L,R,val);
	if(mid<R) update(rson,mid+1,r,L,R,val);
	mn[rt]=min(mn[lson],mn[rson]);
}
double query(cu rt,cu l,cu r,cu L,cu R){
	if(L<=l && r<=R) return mn[rt];
	pd(rt,l,r);
	ui mid=(l+r)>>1;
	double ret=1e18;
	if(L<=mid) ret=min(ret,query(lson,l,mid,L,R));
	if(mid<R) ret=min(ret,query(rson,mid+1,r,L,R));
	return ret;
}
int main(){
	scanf("%d%d",&n,&k);
	for(int i=0;i<=n;i++) scanf("%d%d",&X[i],&Y[i]);
	for(int i=1;i<=n;i++){
		if(i>1) update(1,0,n,max(i-k,0),i-2,dis(X[i-1],Y[i-1],X[i],Y[i]));//回到原点后又出发的点,
		update(1,0,n,i-1,i-1,dis(X[0],Y[0],X[i],Y[i]));//才回到原点的再出发。
		update(1,0,n,i,i,query(1,0,n,max(i-k,0),i-1)+dis(X[0],Y[0],X[i],Y[i]));//寻找距离最小值然后回到原点。
	}
	printf("%.6lf\n",query(1,0,n,n,n));
	return 0;
}
posted @ 2024-01-20 11:45  Chen_Jinhui  阅读(9)  评论(0)    收藏  举报