• [CF1420C2] Pokémon Army (hard version)


    Description

    给定一个长度为 n 的序列 a,有 q 次操作,每次操作交换 a[l],a[r],在操作前和每次操作后求出 a 中所有子序列的交替和((s_1-s_2+s_3-s_4+...))的最大值。

    Solution

    很容易想到线段树维护区间信息,可是这样太暴力了。

    发现所谓子序列的交替和,实际上就是在原数列的差分数列中选出一些段,使得他们的和最小/最大。

    基于上面这个感性的结论,我们可以将原问题转化为,选取若干个位置 (i),使得 (sum_i max(0,a[i]-a[i-1])) 最大。

    显然我们只需要选择那些 (>0) 的部分即可。

    (f(i)=max(0,a[i]-a[i-1])),则每次修改 (l,r) 最多只会影响到 (l,l+1,r,r+1) 四个位置,我们先减去它们的贡献,修改完毕后,再把他们加回去即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long 
    const int N = 1000005;
    
    int n,q,a[N],ans;
    
    int f(int i)
    {
        if(i>n) return 0;
        return max(0ll,a[i]-a[i-1]);
    }
    
    int calc(int x,int y)
    {
        int ans=0;
        ans+=f(x);
        ans+=f(x+1);
        if(y!=x && y!=x+1) ans+=f(y);
        if(y+1!=x && y!=x) ans+=f(y+1);
        return ans; 
    }
    
    void solve()
    {
        cin>>n>>q;
        ans=0;
        for(int i=1;i<=n+2;i++) a[i]=0;
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=1;i<=n;i++) ans+=f(i);
        cout<<ans<<endl;
        while(q--)
        {
            int l,r;
            cin>>l>>r;
            ans-=calc(l,r);
            swap(a[l],a[r]);
            ans+=calc(l,r);
            cout<<ans<<endl;
        }
    }
    
    signed main()
    {
        ios::sync_with_stdio(false);
        int t;
        cin>>t;
        while(t--)
        {
            solve();
        }
    }
    
  • 相关阅读:
    DES算法
    流密码_电子科大慕课笔记_七八讲
    王道考研《2019年操作系统考研复习指导》第一章笔记
    欧拉公式C++实现
    编译原理第一章学习笔记
    leetcode 728. Self Dividing Numbers
    leetcode 942. DI String Match
    2019年第十届蓝桥杯JAVA开发A组第二题
    2019年第十届蓝桥杯JAVA开发A组第一题
    python类的内置方法
  • 原文地址:https://www.cnblogs.com/mollnn/p/13884837.html
Copyright © 2020-2023  润新知