我尽然把一道dp的题用线段树写
nlogn的复杂度还被玄学的卡了一波常
建一棵求区间最大的线段树(我下面的线段树模板支持求区间和,区间最小,区间最大)
也可以自己传函数

用双指针法把每一个区间的值求出来扔进线段树中。

然后遍历每个区间,用当前区间的值加上后面区间的最大值看看能不能更新最大值。
比如说总共有5个区间那就进行如下操作
第1个区间的值+第2-5的区间最大值
第2个区间的值+第3-5的区间最大值
第3个区间的值+第4-5的区间最大值
第4个区间的值+第5-5的区间最大值

这段代码如果T了就多交几发,玄学

//#pragma GCC optimize(2)
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=2e5;

namespace segment_tree
{
    //线段树模板
    template<class T>
    inline void sum_merge(T &a,T &b,T &c)
    {
        a=b+c;
    }

    template<class T>
    inline void sum_lazy_down(T &a,T &b,int n)
    {
        a+=b*n;
    }

    template<class T>
    inline T sum_ask_merge(T a,T b)
    {
        return a+b;
    }

    template<class T>
    inline void min_merge(T &a,T &b,T &c)
    {
        a=min(b,c);
    }

    template<class T>
    inline void min_lazy_down(T &a,T &b,int n)
    {
        a+=b;
    }

    template<class T>
    inline T min_ask_merge(T a,T b)
    {
        return min(a,b);
    }

    template<class T>
    inline void max_merge(T &a,T &b,T &c)
    {
        a=max(b,c);
    }

    template<class T>
    inline void max_lazy_down(T &a,T &b,int n)
    {
        a+=b;
    }

    template<class T>
    inline T max_ask_merge(T a,T b)
    {
        return max(a,b);
    }

    template<class T>
    struct tnode
    {
        T sum,lazy;
        int l,r;
    };

    template<class T>
    class Segment_Tree
    {
    public:
        void(*merge)(T &parent,T &child1,T &child2);//合并时的规则
        void(*lazy_down)(T &value,T &lazy_value,int segment_length);//懒标记下传时的规则
        T(*ask_merge)(T child1,T child2);//询问合并时的规则

        void sum_mode()
        {
            //求和模式
            merge=sum_merge;
            lazy_down=sum_lazy_down;
            ask_merge=sum_ask_merge;
        }

        void min_mode()
        {
            //求最小模式
            merge=min_merge;
            lazy_down=min_lazy_down;
            ask_merge=min_ask_merge;
        }

        void max_mode()
        {
            //求最大模式
            merge=max_merge;
            lazy_down=max_lazy_down;
            ask_merge=max_ask_merge;
        }


        void pushdown(int root)
        {
            //下传
            if(t[root].lazy!=0)
            {
                lazy_down(t[root].sum,t[root].lazy,t[root].r-t[root].l+1);
                if(t[root].l!=t[root].r)
                {
                    int ch=root<<1;
                    t[ch].lazy+=t[root].lazy;
                    t[ch+1].lazy+=t[root].lazy;
                }
                t[root].lazy=0;
            }
        }

        void update (int root)
        {
            //上更新
            int ch=root<<1;
            pushdown(ch);
            pushdown(ch+1);
            merge(t[root].sum,t[ch].sum,t[ch+1].sum);
        }

        void build(int l,int r,int root=1)
        {
            //建树
            t[root].l=l;
            t[root].r=r;
            t[root].sum=0;
            t[root].lazy=0;
            if(l!=r)
            {
                int mid=(l+r)>>1;
                int ch=root<<1;
                build(l,mid,ch);
                build(mid+1,r,ch+1);
                update(root);
            }
        }

        void change(int l,int r,T delta,int root=1)
        {
            if(l>r)
                return ;
            //区间修改
            if(l==t[root].l&&r==t[root].r)
            {
                t[root].lazy+=delta;
                pushdown(root);
                return;
            }
            int mid=(t[root].l+t[root].r)>>1;
            int ch=root<<1;
            if(r<=mid)
                change(l,r,delta,ch);
            else if(l>mid)
                change(l,r,delta,ch+1);
            else
            {
                change(l,mid,delta,ch);
                change(mid+1,r,delta,ch+1);
            }
            update(root);
        }

        T ask(int l,int r,int root=1)
        {
            if(l>r)
                return 0;
            //区间查询
            pushdown(root);
            if(t[root].l==l&&t[root].r==r)
            {
                return t[root].sum;
            }
            int mid=(t[root].l+t[root].r)>>1;
            int ch=root<<1;
            if(r<=mid)
                return ask(l,r,ch);
            else if(l>mid)
                return ask(l,r,ch+1);
            else
                return ask_merge(ask(l,mid,ch),ask(mid+1,r,ch+1));
        }

    private:
        tnode<T> t[4*MAXN];
    };   
}

//快读,不用就T被卡常了   
template<typename T>
inline bool scan_d(T &ret)
{
    char c;
    int sgn;
    if(c=getchar(),c==EOF) //EOF
        return 0;
    while(c!='-'&&(c<'0'||c>'9'))
        c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9')
        ret=ret*10+(c-'0');
    ret*=sgn;
    return 1;
}
template<typename T>
inline void out(T x)
{
    if(x>9)
        out(x/10);
    putchar(x%10+'0');
}


using namespace segment_tree;
int a[MAXN];
int n,k;
Segment_Tree<ll> sg;
void solve()
{
    scan_d(n);
    scan_d(k);
    sg.build(1,n);
    for(int i=1;i<=n;i++)
    {
        scan_d(a[i]);
    }

    //双指针求每个区间的值,扔进线段树中
    ll tmp=0;
    for(int i=1;i<=k;i++)
        tmp+=a[i];
    sg.change(1,1,tmp);
    for(int i=2,j=k+1;j<=n;i++,j++)
    {
        tmp+=-a[i-1]+a[j];
        sg.change(i,i,tmp);
    }

    //这段没用,但是不写就T,我也不知道为什么,玄学
    for(int i=n-k+2;i<=n;i++)
        sg.change(i,i,0xcfcfcfcfcfcfcfcf);


    ll mx=0xcfcfcfcfcfcfcfcf;//注意负数
    for(int i=1;i+k+k-1<=n;i++)
    {
        tmp=sg.ask(i,i)+sg.ask(i+k,n-k+1);//当前区间+后面找最大的区间
        mx=max(mx,tmp);//看能不能更新最大值
    }
    printf("%lld\n",mx);
}

int main()
{
    sg.max_mode();//线段树调到区间最大模式
    int t;
    scan_d(t);
    while(t--)
        solve();
    return 0;
}