C2. Pokémon Army (hard version) (贪心&分治)

思路:局部最优解 → \rightarrow 全局最优解。

显然答案数组长度为奇数,因为 a i > 0 a_i>0 ai>0

考虑小区间 [ i − 1 , 1 + 1 ] [i-1,1+1] [i1,1+1],对于数 a i a_i ai,若 a i a_i ai为波峰, a i > a i − 1 & & a i > a i + 1 a_i>a_{i-1}\&\&a_i>a_{i+1} ai>ai1&&ai>ai+1

显然这样的 a i a_i ai是最优的,与之对应的波谷 a i a_i ai则减去即可。

这样同时保证了答案数组长度为奇数。

对于交换操作,即考虑 a l , a r a_l,a_r al,ar对于答案的影响。

我们在原来的答案上删去 a l , a l − 1 , a l + 1 , a r , a r − 1 , a r + 1 a_l,a_{l-1},a_{l+1},a_r,a_{r-1},a_{r+1} al,al1,al+1,ar,ar1,ar+1的影响。

然后交换 a l , a r a_l,a_r al,ar,再加上 a l , a l − 1 , a l + 1 , a r , a r − 1 , a r + 1 a_l,a_{l-1},a_{l+1},a_r,a_{r-1},a_{r+1} al,al1,al+1,ar,ar1,ar+1的影响即可。

时间复杂度: O ( n ) O(n) O(n)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
#define il inline
int t,n,q,a[N];
ll ans;
void fun(int i,int op){
	if(a[i]>a[i-1]&&a[i]>a[i+1]) ans+=op*a[i];
	if(a[i]<a[i-1]&&a[i]<a[i+1]) ans-=op*a[i];
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&q);a[0]=a[n+1]=-1;ans=0;
		for(int i=1;i<=n;i++)
			scanf("%d",&a[i]);
		for(int i=1;i<=n;i++) fun(i,1);
		printf("%lld\n",ans);
		while(q--){
			int l,r;scanf("%d%d",&l,&r);
			fun(l,-1),fun(l-1,-1),fun(l+1,-1);
			if(l+1<r-1) fun(r-1,-1);
			if(l+1<r) fun(r,-1);
			fun(r+1,-1);
			swap(a[l],a[r]);
			fun(l,1),fun(l-1,1),fun(l+1,1);
			if(l+1<r-1) fun(r-1,1);
			if(l+1<r) fun(r,1);
			fun(r+1,1);
			printf("%lld\n",ans); 
		}
	}
	return 0;
}