#pragma GCC optimize(3)
#include
using namespace std;
const int maxn=2000001;
int n,a[maxn],m;
struct node {
int minn,lazy;//minn 维护的最小值,lazy 懒惰标记
} t[maxn<<2];
int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0')
{
x=x*10+ch-48;
ch=getchar();
}
return x*f;
}
inline int lc(int p) {//左孩子 l=2*p;
return p<<1;
}
inline int rc(int p) {//右孩子 l=2*p+1;
return p<<1|1;
}
inline void push_up(int p) {
t[p].minn=min(t[lc(p)].minn,t[rc(p)].minn);//维护父亲节点
}
inline void build(int p,int l,int r) {//建树
t[p].lazy=0;
if(l==r) {// 左孩子和右孩子相等,到达最低端,区间最小值就是a[l]
t[p].minn=a[l];
return ;
}
int mid=(l+r)>>1;
build(lc(p),l,mid);//左孩子
build(rc(p),mid+1,r);//右孩子
push_up(p);//向上维护父亲节点
}
inline void mark(int p,int k) {//记录当前节点所代表的区间
t[p].lazy+=k;
t[p].minn+=k;
}
inline void push_down(int p) {//懒惰标记下放
mark(lc(p),t[p].lazy);
mark(rc(p),t[p].lazy);
t[p].lazy=0;
}
inline void update(int x,int y,int l,int r,int p) {//区间修改
if(x<=l&&r<=y) {
mark(p,t[p].lazy);
}
push_down(p);
int mid=(l+r)>>1;
if(x<=mid) update(x,y,l,mid,p);
if(y>mid) update(x,y,mid+1,r,p);
push_up(p);
}
inline int query(int x,int y,int l,int r,int p) {//区间查询
if(x<=l&&y>=r) {
return t[p].minn;
}
push_down(p);
int mid=(l+r)>>1;
if(y<=mid) return query(x,y,l,mid,lc(p));
else if(x>mid) return query(x,y,mid+1,r,rc(p));
else return min(query(x,y,l,mid,lc(p)),query(x,y,mid+1,r,rc(p)));
}
int main() {
scanf("%d%d",&n,&m);
for(register int i=1; i<=n; i++)
scanf("%d",&a[i]);
build(1,1,n);
printf("0\n");//第一个点输出0
for(register int i=2; i<=n; i++) {
printf("%d\n",query(i-m>0?i-m:1,i-1,1,n,1));//左区间分两种情况,i-m<0 左区间为1 i-m>0 左区间为i-m
}
return 0;
}
希望对各位新学线段树的萌新有帮助