P4062 [Code+#1]Yazid 的新生舞会(线段树做法)

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4062 [Code+#1]Yazid 的新生舞会(线段树做法)相关的知识,希望对你有一定的参考价值。

P4062 [Code+#1]Yazid 的新生舞会(线段树做法)

题意:

给你一个序列a[1…n]​,求存在绝对众数的子区间个数。

绝对众数指:区间中出现次数最多的那个数,出现次数严格大于区间长度的一半。

题解:

这两个博客将的很长清楚明白(尤其是第一个),我在反复看了n遍后,终于明白。题目细节很多,我再怎么写也没这两个详细,干脆直接放上链接。
Zechariah的博客
OMG_wc 的博客
关于题解中提到的三阶前缀和:
三阶前缀和公式转换:
图来自lx_tyin博客

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
const int N = 500005;
// 修改差分 来维护前缀和的前缀和
// c1 为差分d c2为d*i  c3 为d*i*i
LL c1[N * 2], c2[N * 2], c3[N * 2];
LL sum(int x) {
    LL res = 0;
    for (int i = x; i > 0; i -= i & -i) {
        res += c1[i] * (x + 2) * (x + 1) - c2[i] * (2 * x + 3) + c3[i];
    }
    return res / 2;
}
void add(int x, LL d, int n) {
    for (int i = x; i <= n; i += i & -i) {
        c1[i] += d;
        c2[i] += d * x;
        c3[i] += d * x * x;
    }
}
int a[N];
vector<int> b[N];
int main() {
    int n;
    scanf("%d%*d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        b[a[i]].push_back(i);
    }
    const int wc = n + 1;  // 偏移量,把[-n,n] 平移到 [1,2n+1]
    LL ans = 0;
    for (int i = 0; i < n; i++) {
        b[i].push_back(n + 1);
        int last = 0;
        for (int j = 0; j < b[i].size(); j++) {
        	//j表示i的个数
            int y = 2 * j - last + wc;
            int x = 2 * j - (b[i][j] - 1) + wc;
            // 查询 sum([1,t-1] 的权值和), 其中t在[x,y]范围内,
            ans += sum(y - 1) - (x >= 3 ? sum(x - 2) : 0);
            // [x,y] 这些数的权值+1
            add(x, 1, 2 * n + 1);
            add(y + 1, -1, 2 * n + 1);
            last = b[i][j];
        }
        
        //撤销操作
        last = 0;
        for (int j = 0; j < b[i].size(); j++) {
            int y = 2 * j - last + wc;
            int x = 2 * j - (b[i][j] - 1) + wc;
            add(x, -1, 2 * n + 1);
            add(y + 1, 1, 2 * n + 1);
            last = b[i][j];
        }
    }
    printf("%lld\\n", ans);
    return 0;
}

以上是关于P4062 [Code+#1]Yazid 的新生舞会(线段树做法)的主要内容,如果未能解决你的问题,请参考以下文章

luogu P4062 [Code+#1]Yazid 的新生舞会(线段树+套路)

洛谷 - P4062 [Code+#1]Yazid 的新生舞会(推公式+线段树)

BZOJ5110[CodePlus2017]Yazid 的新生舞会 线段树

Yazid的新生舞会(线段树)

bzoj5110[CodePlus2017]Yazid 的新生舞会 Treap

「CodePlus 2017 11 月赛」Yazid 的新生舞会(树状数组/线段树)