题解 [ABC334F] Christmas Present 2
cjh20090318 · · 题解
有一定难度的 ABC F。
题意
翻译很清楚。
标签:动态规划、线段树。
分析
设
在第
区间加和,区间查询,这个直接用线段树维护即可。
时间复杂度
代码
//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;
}