← 回到所有文章

AT_abc390_f [ABC390F] Double Sum 3 点边容斥做法 题解

首先我们了解一下点边容斥,目标是数一个树上的联通块个数,我们知道一棵树有 n 个点,那么就有 n-1 条边,所以只需要数所有的点个数减去所有的边个数就行。 那么这道题实际上是一条链数联通块,那么同样这…

题解文章的简约插画封面

首先我们了解一下点边容斥,目标是数一个树上的联通块个数,我们知道一棵树有 nn 个点,那么就有 n−1n-1 条边,所以只需要数所有的点个数减去所有的边个数就行。

那么这道题实际上是一条链数联通块,那么同样这样数就行,从左到右扫描线,记录每个点 aia_i 上一次出现的位置 paip_{a_i},那么固定 RR 到 ii,对于所有的 LL,会贡献 i−paii-p_{a_i} 个点。

现在来看边,会影响的只有两条边,到 ai−1a_i-1 和 ai+1a_i+1,分析一下到 ai−1a_i-1,那么需要算出 L∈(pai,i]L\in(p_{a_i},i] 贡献多少条边,那么就是 max⁡(pai−1−pai,0)\max(p_{a_{i}-1}-p_{a_i},0),到 ai+1a_i+1 同理。

代码很简洁,轻松最优解:

#include<bits/stdc++.h>

int pre[300010];

int main(){
    int i,j,a,n;
    long long res=0,cnt=0;
	scanf("%d",&n);
    for(i=1;i<=n;++i) scanf("%d",&a),res+=(cnt+=i-pre[a]-std::max(pre[a-1]-pre[a],0)-std::max(pre[a+1]-pre[a],0)),pre[a]=i;

    printf("%lld",res);

    return 0;
}

谢谢你,读到这里。

本文同步自洛谷专栏,保留原始正文与发布时间。在洛谷查看原文 ↗

搜索文章

输入关键词,发现一些值得阅读的文字。

探索文字里的小小世界esc 关闭