Loading

C. Monoblock(贡献 子段) CF 1715C

题目:

​ 给出长度为n的序列,计算其所有子段的答案和\((\sum_{l=1}^{n}\sum_{r=l}^n g(l, r))\)。对于子段\([l, r]\)的计算公式\(g(l, r)\)=l到r之间合并后的块数。
合并:对于\(i\) \((2 <= n)\),若\(a_i = a_i-1\),他们可以被看做是同一块。

分析:

​ 可以通过\(n^2\)的暴力计算得到答案,但是这样做时间复杂度会非常高,所以我们要想办法优化。由于每次只对一个数值进行修改,所以很容易将思维转化到计算贡献上。我们一开始可以用\(O(n)\)来预处理出初始状态的答案,然后对于每一次的修改,我们要对其进行贡献的修正,若是原本是相同,改后是不相同,那就要加上贡献,若是原本不相同,改后相同,那就要减去贡献。对于一个位置上的修改,要考虑修改前后他与左右的关系。

实现:

​ 那么我们已经得到了一个思路,但是计算贡献又是一个难题。对于初始状态来说,假设现在整段都是1,那么他的贡献为\(\sum_{i=1}^{n}i\),那么当\(a_i\)\(a_{i-1}\)不同的时候,\(l\)的取值范围是\([1, i - 1]\)\(r\)的取值范围是\([i,n]\),那么这对数对于\((i-1)*(n-i+1)\)个子段贡献+1。那么初始化就做好了。

​ 接下来看修改的部分,若\(i\)被修改的时候,分别讨论左和右的情况,计算其影响的子段数量,从而得到总贡献的增减情况。

#include <bits/stdc++.h>
    
using namespace std;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define all(x) x.begin(), x.end()
#define pb push_back
#define ios ios::sync_with_stdio(false);cin.tie(0);
#define debug(x)    cout << x << endl;
#define SZ(x)    (int)x.size()
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int inf = 0x3f3f3f3f;
void read(int &x) {int s = 0, f = 1; char ch = getchar(); while(!isdigit(ch)) {f = (ch == '-' ? -1 : f); ch = getchar();} while(isdigit(ch)) {s = s * 10 + ch - '0'; ch = getchar();} x = s * f;}

const int N = 100005;
int n, m;
int a[N];
LL res = 0;

void init()
{
    for(int i = 2; i <= n; i ++)
        if(a[i - 1] != a[i])
            res += 1ll * (i - 1) * (n - i + 1);
}

signed main()
{
    scanf("%d%d", &n, &m);
    res = 1ll * n * (n + 1) / 2; //初始贡献
    for(int i = 1; i <= n; i ++)
        scanf("%d", &a[i]);
    init(); //初始化贡献

    while(m --)
    {
        int idx, val;
        scanf("%d%d", &idx, &val);
        if(idx > 1 && a[idx] != a[idx - 1])
            res -= 1ll * (idx - 1) * (n - idx + 1);
        if(idx < n && a[idx] != a[idx + 1])
            res -= 1ll * idx * (n - idx);
        a[idx] = val; 
        if(idx > 1 && a[idx] != a[idx - 1])
            res += 1ll * (idx - 1) * (n - idx + 1);
        if(idx < n && a[idx] != a[idx + 1])
            res += 1ll * idx * (n - idx);
        printf("%lld\n", res);
    }   
}
posted @ 2022-09-01 16:29  DM11  阅读(50)  评论(0编辑  收藏  举报