Codeforces1420 C2. Pokémon Army (hard version)(差分)

This is the hard version of the problem. The difference between the versions is that the easy version has no swap operations. You can make hacks only if all versions of the problem are solved.

Pikachu is a cute and friendly pokémon living in the wild pikachu herd.

But it has become known recently that infamous team R wanted to steal all these pokémon! Pokémon trainer Andrew decided to help Pikachu to build a pokémon army to resist.

First, Andrew counted all the pokémon — there were exactly 𝑛 pikachu. The strength of the 𝑖-th pokémon is equal to 𝑎𝑖, and all these numbers are distinct.

As an army, Andrew can choose any non-empty subsequence of pokemons. In other words, Andrew chooses some array 𝑏 from 𝑘 indices such that 1≤𝑏1<𝑏2<⋯<𝑏𝑘≤𝑛, and his army will consist of pokémons with forces 𝑎𝑏1,𝑎𝑏2,…,𝑎𝑏𝑘.

The strength of the army is equal to the alternating sum of elements of the subsequence; that is, 𝑎𝑏1−𝑎𝑏2+𝑎𝑏3−𝑎𝑏4+….

Andrew is experimenting with pokémon order. He performs 𝑞 operations. In 𝑖-th operation Andrew swaps 𝑙𝑖-th and 𝑟𝑖-th pokémon.

Andrew wants to know the maximal stregth of the army he can achieve with the initial pokémon placement. He also needs to know the maximal strength after each operation.

Help Andrew and the pokémon, or team R will realize their tricky plan!

Input
Each test contains multiple test cases.

The first line contains one positive integer 𝑡 (1≤𝑡≤103) denoting the number of test cases. Description of the test cases follows.

The first line of each test case contains two integers 𝑛 and 𝑞 (1≤𝑛≤3⋅105,0≤𝑞≤3⋅105) denoting the number of pokémon and number of operations respectively.

The second line contains 𝑛 distinct positive integers 𝑎1,𝑎2,…,𝑎𝑛 (1≤𝑎𝑖≤𝑛) denoting the strengths of the pokémon.

𝑖-th of the last 𝑞 lines contains two positive integers 𝑙𝑖 and 𝑟𝑖 (1≤𝑙𝑖≤𝑟𝑖≤𝑛) denoting the indices of pokémon that were swapped in the 𝑖-th operation.

It is guaranteed that the sum of 𝑛 over all test cases does not exceed 3⋅105, and the sum of 𝑞 over all test cases does not exceed 3⋅105.

Output
For each test case, print 𝑞+1 integers: the maximal strength of army before the swaps and after each swap.

Example
inputCopy
3
3 1
1 3 2
1 2
2 2
1 2
1 2
1 2
7 5
1 2 5 4 3 6 7
1 2
6 7
3 4
1 2
2 3
outputCopy
3
4
2
2
2
9
10
10
10
9
11
Note
Let’s look at the third test case:

Initially we can build an army in such way: [1 2 5 4 3 6 7], its strength will be 5−3+7=9.

After first operation we can build an army in such way: [2 1 5 4 3 6 7], its strength will be 2−1+5−3+7=10.

After second operation we can build an army in such way: [2 1 5 4 3 7 6], its strength will be 2−1+5−3+7=10.

After third operation we can build an army in such way: [2 1 4 5 3 7 6], its strength will be 2−1+5−3+7=10.

After forth operation we can build an army in such way: [1 2 4 5 3 7 6], its strength will be 5−3+7=9.

After all operations we can build an army in such way: [1 4 2 5 3 7 6], its strength will be 4−2+5−3+7=11.

题意:
有一个a序列,要你找一个子序列,结果为奇数位减去偶数位的和。求最大和。
同时还有交换操作,求出操作后的最大和。

思路:
如果没有交换操作,那就可以直接dp。定义 d p [ i ] [ 0 ] dp[i][0] dp[i][0]为前 i i i个数选择了偶数个数的最大和, d p [ i ] [ 1 ] dp[i][1] dp[i][1]为选择了奇数个数的最大和。
转移就是
d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 0 ] + a [ i ] ) ; dp[i][1] = max(dp[i-1][1],dp[i - 1][0] + a[i]); dp[i][1]=max(dp[i1][1],dp[i1][0]+a[i]);
d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] − a [ i ] ) ; dp[i][0] = max(dp[i-1][0],dp[i - 1][1] - a[i]); dp[i][0]=max(dp[i1][0],dp[i1][1]a[i]);

因为c1写了dp,所以c2加上交换操作的时候一直考虑能不能线段树维护这个dp数组。。。


最后序列实际可以写成上升下降的波形,也就是存在波峰波谷。
在这里插入图片描述

首先可以确定最终结果一定是奇数个数(偶数个数的最后一个数负数,肯定没用)

假设将序列分为两段 [ 1 , l ] [1,l] [1,l], [ l + 1 , n ] [l+1,n] [l+1,n],那么最终的序列分配为

  1. 左偶数+右奇数
  2. 左奇数-右偶数

我们将 a a a序列分为很多段考虑,每段都单调递增或者递减,序列由这些段拼接起来。这样考虑的理由是,每个单调段的偶数和和奇数和可以直接算出来。

假设我们已经算出 [ 1 , x ] [1,x] [1,x]的结果,现在多了接着往后添加一段单调序列 [ x + 1 , y ] [x+1,y] [x+1,y]
不妨假设 [ x + 1 , y ] [x+1,y] [x+1,y]单调递增,且 [ 1 , x ] [1,x] [1,x]结尾单调递减。

也就是尾部长这样。
在这里插入图片描述

红点处代表x+1。

假设 [ 1 , x ] [1,x] [1,x]部分奇数最大值为 x 1 x1 x1,偶数值取为 x 1 − a [ x ] x1-a[x] x1a[x](这个值不是偶数最大值,但是可以取到,因为按照这样的结构,奇数最后一个数肯定不是a[x])。

[ x + 1 , y ] [x+1,y] [x+1,y]奇数最大值为 a [ y ] a[y] a[y],偶数最小值为 a [ x + 1 ] − a [ y ] a[x+1]-a[y] a[x+1]a[y]

则有

  1. 左偶数+右奇数: x 1 − a [ x ] + a [ y ] x1-a[x]+a[y] x1a[x]+a[y]
  2. 左奇数-右偶数: x 1 − a [ x + 1 ] + a [ y ] x1-a[x+1]+a[y] x1a[x+1]+a[y]

很明显是左偶数右奇数结果更优。

同理,你可以在 y y y的结尾再加上一段递减序列组成^型结构进行计算。

最后可以得到,结果实际上就是每个波峰减去波谷的结果和再加上最后一个点。
这个过程可以用差分数组维护,实际就是差分数组的正数项和。

c2差分写法

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

typedef long long ll;
const int maxn = 3e5 + 7;
const int mod = 1e9 + 7;

int a[maxn],b[maxn];

int main() {
    int T;scanf("%d",&T);
    while(T--) {
        int n,m;scanf("%d%d",&n,&m);
        for(int i = 1;i <= n;i++) {
            scanf("%d",&a[i]);
        }
        a[n + 1] = 0;
        for(int i = n;i >= 1;i--) {
            b[i] = a[i] - a[i + 1];
        }
        ll ans = 0;
        for(int i = 1;i <= n;i++) {
            if(b[i] > 0) ans += b[i];
        }
        printf("%lld\n",ans);
        for(int i = 1;i <= m;i++) {
            int x,y;scanf("%d%d",&x,&y);
            if(x > y) swap(x,y);
            for(int j = max(1,x - 1);j <= min(n,x + 1);j++) {
                if(b[j] > 0) ans -= b[j];
            }
            for(int j = max(x + 2,y - 1);j <= min(n,y + 1);j++) {
                if(b[j] > 0) ans -= b[j];
            }
            swap(a[x],a[y]);
            
            for(int j = max(1,x - 1);j <= min(n,x + 1);j++) {
                b[j] = a[j] - a[j + 1];
            }
            for(int j = max(x + 2,y - 1);j <= min(n,y + 1);j++) {
                b[j] = a[j] - a[j + 1];
            }
            
            
            for(int j = max(1,x - 1);j <= min(n,x + 1);j++) {
                if(b[j] > 0) ans += b[j];
            }
            for(int j = max(x + 2,y - 1);j <= min(n,y + 1);j++) {
                if(b[j] > 0) ans += b[j];
            }
            
            printf("%lld\n",ans);
        }
    }
    return 0;
}


c1 DP写法

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

typedef long long ll;
const int maxn = 3e5 + 7;
const int mod = 1e9 + 7;

ll dp[maxn][2];//0偶数,1奇数
int a[maxn];

int main() {
    int T;scanf("%d",&T);
    while(T--) {
        int n,m;scanf("%d%d",&n,&m);
        for(int i = 1;i <= n;i++) {
            scanf("%d",&a[i]);
            dp[i][0] = dp[i][1] = 0;
        }
        dp[1][1] = a[1];
        for(int i = 2;i <= n;i++) {
            dp[i][1] = dp[i - 1][1];
            dp[i][0] = dp[i - 1][0];
            dp[i][1] = max(dp[i][1],dp[i - 1][0] + a[i]);
            dp[i][0] = max(dp[i][0],dp[i - 1][1] - a[i]);
        }
        printf("%lld\n",max(dp[n][0],dp[n][1]));
    }
    return 0;
}

根据提供的引用内容,Codeforces Round 511 (Div. 1)是一个比赛的名称。然而,引用内容中没有提供与这个比赛相关的具体信息或问题。因此,我无法回答关于Codeforces Round 511 (Div. 1)的问题。如果您有关于这个比赛的具体问题,请提供更多的信息,我将尽力回答。 #### 引用[.reference_title] - *1* [Codeforces Round 860 (Div. 2)题解](https://blog.csdn.net/qq_60653991/article/details/129802687)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces Round 867 (Div. 3)(A题到E题)](https://blog.csdn.net/wdgkd/article/details/130370975)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Codeforces Round 872 (Div. 2)(前三道](https://blog.csdn.net/qq_68286180/article/details/130570952)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值