简易版显然是dp了
加强版可以用差分(但我不会)
看到一种线段树的写法 比差分好写 讨论少
众所周知最大子列和是可以用线段树动态维护的
然后这题和最大子列和其实差不多
维护
++ +- -+ --这四种情况 然后合并就可以了
比赛的时候脑抽了 想着维护奇数和和偶数和可以
像这种需要合并的 我们都得清楚边界情况是啥 才能保证合并的准确性
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+100;
typedef long long ll;
struct node{
ll zz,zf,fz,ff;
int l,r;
}T[N<<2];
ll a[N];
const ll inf = 1e15;
#define ls id<<1
#define rs ls|1
void pushup(int id){
T[id].zz=max({T[ls].zz,T[rs].zz,T[ls].zf+T[rs].zz,T[ls].zz+T[rs].fz});
T[id].zf=max({T[ls].zf,T[rs].zf,T[ls].zz+T[rs].ff,T[ls].zf+T[rs].zf});
T[id].fz=max({T[ls].fz,T[rs].fz,T[ls].ff+T[rs].zz,T[ls].fz+T[rs].fz});
T[id].ff=max({T[ls].ff,T[rs].ff,T[ls].ff+T[rs].zf,T[ls].fz+T[rs].ff});
//printf("l=%d r=%d\n",T[id].l,T[id].r);
//printf("zz=%lld zf=%lld fz=%lld ff=%lld\n",T[id].zz,T[id].zf,T[id].fz,T[id].ff);
}
void build(int id,int l,int r){
T[id].l=l,T[id].r=r;
if(l==r){
T[id].zz=a[l];
T[id].zf=-inf;
T[id].fz=-inf;
T[id].ff=-a[l];
return;
}
int mid = l+r>>1;
build(ls,l,mid);build(rs,mid+1,r);
pushup(id);
}
void update(int id,int pos,ll v){
if(T[id].l==T[id].r){
T[id].zz=v;
T[id].zf=-inf;
T[id].fz=-inf;
T[id].ff=-v;
return;
}
int mid = T[id].l+T[id].r>>1;
if(pos<=mid) update(ls,pos,v);
else update(rs,pos,v);
pushup(id);
}
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,q;
scanf("%d%d",&n,&q);
for(int i = 1; i <= n; i++) scanf("%lld",&a[i]);
build(1,1,n);
printf("%lld\n",T[1].zz);
for(int i = 1; i <= q; i++){
int l,r;
scanf("%d%d",&l,&r);
update(1,l,a[r]);
update(1,r,a[l]);
swap(a[l],a[r]);
printf("%lld\n",T[1].zz);
}
}
return 0;
}
/*
22
7 0
1 2 5 4 3 6 7
*/