[分块处理] Color

来源:互联网 发布:如何获得淘宝内部优惠 编辑:程序博客网 时间:2024/06/05 09:14
Task  Color【题目描述】   给定一个长度为N的颜色序列C,对于该序列中的任意一个元素Ci,都有1<=Ci<=M。对于一种颜色ColorK来说,区间[L,R]内的权值定义为这种颜色在该区间中出现的次数的平方,即区间[L,R]内中满足Ci=ColorK的元素个数的平方。接下来给出Q个询问,询问区间[L,R]内颜色[a,b]的权值总和。【输入数据】第1行三个整数N,M,Q。分别代表序列长度,颜色总数和询问总数。第2行N个整数,代表序列Ci。第3行到第Q+2行,每行4个整数l,r,a,b。记上一次计算出的答案为Lans。那么实际的l,r,a,b为给出的l,r,a,b分别xor上Lans。第一个询问的时候Lans=0。【输出数据】总共Q行,对于每一个询问,输出权值总和。【样例输入】4 2 31 1 2 2 1 4 1 210 11 9 103 0 0 0【样例输出】820【数据范围】40% :1<=N,Q<=10000100%:1<=N,Q<=50000

一开始看到数据范围线段树是会挂的,有想到过分块处理,但是实在想不出平方和怎么一起计算出来,所以写了个暴力树状数组(其实根本不用)交了。

之后 Orz cwx,得知可以分段预处理每一段颜色的平方前缀和,对于块之外的杂碎,O(段长) 扫一遍即可, 每遇到一个答案加上原计数器 * 2 + 1,++ 原计数器即可。

然后就开始写了。。。。。写完还是觉得实在不喜欢分段,觉得无论是时间还是空间还是操作都太奇怪了。

#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#define swap(a, b, t) ({t _ = a; a = b; b = _;})#define max(a, b) ({int _ = (a), __ = (b); _ > __ ? _ : __;})#define min(a, b) ({int _ = (a), __ = (b); _ < __ ? _ : __;})#define maxs 26#define maxl 2000#define maxn 50005#define getbl(a) (((a) - 1) / maxl + 1)int n, m, t, Q, ans;int a[maxn], f[maxn], g[maxn], sta[maxn];int b[maxs][maxn];int c[maxs][maxs][maxn], d[maxs][maxs][maxn];void work(){    for (int l, r, x, y; Q --; )    {        scanf("%d%d%d%d", & l, & r, & x, & y);        l ^= ans, r ^= ans, x ^= ans, y ^= ans;        int ll = (l - 2) / maxl + 2, rr = r / maxl;        if (ll <= rr)        {            ans = c[ll][rr][y] - c[ll][rr][x - 1];            for (int i = l, j = (ll - 1) * maxl; i <= j; ++ i)                if (x <= a[i] && a[i] <= y)                {                    if (g[a[i]] != Q + 1) f[a[i]] = d[ll][rr][a[i]], g[a[i]] = Q + 1;                    ans += f[a[i]] ++ * 2 + 1;                }            for (int i = r, j = rr * maxl + 1; i >= j; -- i)                if (x <= a[i] && a[i] <= y)                {                    if (g[a[i]] != Q + 1) f[a[i]] = d[ll][rr][a[i]], g[a[i]] = Q + 1;                    ans += f[a[i]] ++ * 2 + 1;                }        }        else        {            ans = t = 0;            for (int i = l; i <= r; ++ i)                if (x <= a[i] && a[i] <= y)                    if (g[a[i]] == Q + 1) ++ f[a[i]];                    else g[a[i]] = Q + 1, f[a[i]] = 1, sta[++ t] = a[i];            for (int i = 1; i <= t; ++ i)                ans += f[sta[i]] * f[sta[i]];        }        printf("%d\n", ans);    }}void init(){    scanf("%d%d%d", & n, & m, & Q), t = getbl(n);    for (int i = 1; i <= n; ++ i)        scanf("%d", & a[i]), ++ b[getbl(i)][a[i]];    for (int i = 1; i <= t; ++ i)        for (int j = 1; j <= m; ++ j) b[i][j] += b[i - 1][j];    for (int i = 1; i <= t; ++ i)        for (int j = i; j <= t; ++ j)            for (int k = 1; k <= m; ++ k)            {                c[i][j][k] = d[i][j][k] = b[j][k] - b[i - 1][k];                c[i][j][k] *= c[i][j][k - 0];                c[i][j][k] += c[i][j][k - 1];            }}int main(){    freopen("color.in", "r", stdin);    freopen("color.out", "w", stdout);        init();    work();        return 0;}



原创粉丝点击