Maximum Subarray

线段树求最大子段和的板子

枚举每个长度为k的区间

// Problem: Maximum Subarray
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF1796D
// Memory Limit: 500 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<iostream>
#include<algorithm>
#define INF (1ll<<60)
using namespace std;
typedef long long ll;
const int N=2e5+9;
int a[N];
struct node{
	int l,r;
	ll lmx,rmx,sum;
	ll ans;
}seg[N<<2];
ll tl(ll x){return x<<1;}
ll tr(ll x){return x<<1|1;}
void pushup(node &id,node &l,node &r){
	id.sum=l.sum+r.sum;
    id.lmx=max(l.lmx,l.sum+r.lmx);
    id.rmx=max(r.rmx,r.sum+l.rmx);
    id.ans=max(max(l.ans,r.ans),l.rmx+r.lmx);
}
void pushup(int id){
	pushup(seg[id],seg[tl(id)],seg[tr(id)]);
}
void build(int id,int l,int r){
	seg[id]={l,r,0,0,0,0};
	if(l==r){
		seg[id]={l,r,a[l],a[l],a[l],a[l]};
		return;
	}
	int mid=(l+r)>>1;
	build(tl(id),l,mid);
	build(tr(id),mid+1,r);
	pushup(id);
}
node query(int id,int l,int r){
	if(seg[id].l>=l && seg[id].r<=r){
		return seg[id];
	}else{
		int mid=(seg[id].l+seg[id].r)>>1;
		if(mid>=r){
			return query(tl(id),l,r);
		}else if(mid<l){
			return query(tr(id),l,r);			
		}else{
			node res;
			node left=query(tl(id),l,r);
			node right=query(tr(id),l,r);
			pushup(res,left,right);
			return res;			
		}
	}
}
void update(int id,int l,int r,int pos,ll v){
	if(l==r){
		ll t=seg[id].lmx+v;
		seg[id]={l,r,t,t,t,t};
		return;
	}
	int mid=(l+r)>>1;
	if(mid>=pos){
		update(tl(id),l,mid,pos,v);
	}else{
		update(tr(id),mid+1,r,pos,v);
	}
	pushup(id);
}
void solve(){
	int n,k,x;
	cin>>n>>k>>x;
	if(x<0){
		x=-x;
		k=n-k;
	}
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(i<=k){
			a[i]+=x;
		}else{
			a[i]-=x;
		}
	}
	build(1,1,n);
	ll ans=max(0ll,seg[1].ans);
	for(int i=2;i<=n-k+1;i++){
		update(1,1,n,i-1,-2*x);
		update(1,1,n,i+k-1,2*x);
		ans=max(ans,seg[1].ans);
	}
	cout<<ans<<'\n';
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值