思路是如果从0转移说明这是第一个,多建了一个n+1号点,意思就是查询前面的所有最小值。
但是我们老师讲的是每一轮都要求一次min,因为不一定是建立k次,但是我却直接输出f[n]就通过了。
#include <bits/stdc++.h>
#define ls k<<1
#define rs k<<1|1
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define pb emplace_back
using namespace std;
const int N=2e4+5,inf=1e9;
int n,K;
struct node{
int d,c,s,w;
}a[N];
struct tree{
int mn,lz;
tree(){mn=lz=0;}
}tr[N<<2];
int f[N];
void pu(int k)
{
tr[k].mn=min(tr[ls].mn,tr[rs].mn);
}
void pd(int k)
{
if(tr[k].lz)
{
tr[ls].lz+=tr[k].lz;
tr[rs].lz+=tr[k].lz;
tr[ls].mn+=tr[k].lz;
tr[rs].mn+=tr[k].lz;
tr[k].lz=0;
}
}
void add(int k,int l,int r,int L,int R,int vl)
{
if(L>R)
return;
if(R<l || r<L)
return;
if(L<=l && r<=R)
{
tr[k].mn+=vl;
tr[k].lz+=vl;
return;
}
pd(k);
int mid=l+r>>1;
add(ls,l,mid,L,R,vl);
add(rs,mid+1,r,L,R,vl);
pu(k);
}
int query(int k,int l,int r,int L,int R)
{
if(R<l || r<L)
return inf;
if(L<=l && r<=R)
return tr[k].mn;
pd(k);
int mid=l+r>>1;
return min(query(ls,l,mid,L,R),query(rs,mid+1,r,L,R));
}
int le[N],ri[N];
vector<pii>ned[N];
void build(int k,int l,int r)
{
tr[k].lz=0;
if(l==r)
{
tr[k].mn=f[l];
return;
}
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pu(k);
}
int ans=inf;
int main()
{
scanf("%d%d",&n,&K);
a[1].d=0;
for(int i=2;i<=n;i++)
scanf("%d",&a[i].d);
for(int i=1;i<=n;i++)
scanf("%d",&a[i].c);
for(int i=1;i<=n;i++)
scanf("%d",&a[i].s);
for(int i=1;i<=n;i++)
scanf("%d",&a[i].w);
n++;
a[n].d=inf;
a[n].w=inf;
a[n].c=0;
//puts("");
for(int i=1;i<=n;i++)
{
int ll=a[i].d-a[i].s,rr=a[i].d+a[i].s;
le[i]=1;
for(int j=i;j>=1;j--)
if(a[j-1].d<ll)
{
le[i]=j;
break;
}
ri[i]=n;
for(int j=i;j<=n;j++)
if(a[j+1].d>rr)
{
ri[i]=j;
break;
}
ned[ri[i]+1].pb(mp(le[i]-1,a[i].w));
//cout<<le[i]<<' '<<ri[i]<<'\n';
}
//puts("");
for(int i=1,sum=0;i<=n;i++)
{
f[i]=sum+a[i].c;
for(auto v:ned[i])
sum+=v.se;
}
for(int j=2;j<=K+1;j++)
{
build(1,0,n);
for(int i=1;i<=n;i++)
{
for(auto v:ned[i])
add(1,0,n,0,v.fi,v.se);
f[i]=query(1,0,n,0,i-1)+a[i].c;
}
//ans=min(ans,f[n]);
}
printf("%d",f[n]);
return 0;
}