颜色

颜色

题目描述

给定一个长度为 \(N\) 的颜色序列 \(C\),对于该序列中的任意一个元素,都有 \(1\leq Ci \leq M\)。对于一种颜色 \(ColorK\) 来说,区间 \([L,R]\) 内的权值定义为这种颜色在该区间中出现的次数的平方,即区间 \([L,R]\) 内中满足等于 \(ColorK\) 的元素个数的平方。

接下来给出 \(Q\) 个询问,询问区间 \([L,R]\) 内颜色 \([a,b]\) 的权值总和。

输入格式

\(1\) 行三个整数 \(N,M,Q\)
分别代表序列长度,颜色总数和询问总数。

\(2\)\(N\) 个整数,代表序列。

\(3\) 行到第 \(Q+2\) 行,每行 \(4\) 个整数 \(l,r,a,b\)。记上一次计算出的答案为 \(Lans\)。那么实际的 \(l,r,a,b\) 为给出 \(l,r,a,b xor\)\(Lans\)。第一个询问的时候 \(Lans=0\)

输出格式

总共 \(Q\) 行,对于每一个询问,输出权值总和。

样例 #1

样例输入 #1

4 2 3
1 1 2 2 
1 4 1 2
10 11 9 10
3 0 0 0

样例输出 #1

8
2
0

提示

\(1 \leq N,Q \leq 50000,M \leq 20000\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>

using namespace std;

int n, m, q, block;
int c[5211314], pos[5211314];
int pre[102][102][13140 * 2], sum[102][13140 * 2];


inline int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f *= -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch - '0');
		ch = getchar();
	}
	return x * f;
}

inline void Pretreatment() {
	for (int k = 1; k <= 20001; ++ k) {
		for(int i = 1; i <= pos[n]; ++ i) {
			sum[i][k] += sum[i - 1][k];
            //sum[i][k]表示前i个块有几个k
		}
	}
	for (int i = 1; i <= pos[n]; ++ i) {
		for (int j = i; j <= pos[n]; ++ j) {
			for(int k = 1; k <= 20001; ++ k) {
				pre[i][j][k] = pow((sum[j][k] - sum[i - 1][k]), 2) + pre[i][j][k - 1];
                //pre[i][j][k]表示i到j的块中1到k的权值总和
			}
		}
	}
	return;
}

inline int Ask(int lift, int right, int minn, int maxn) {
	int l = pos[lift], r = pos[right], nowans = 0, temp[20001] = {};
	if (l == r) {
		for (int i = lift; i <= right; ++ i) {
			if (c[i] >= minn && c[i] <= maxn) {
                //注意判断
				nowans = nowans + 2 * temp[c[i]] * 1 + 1 * 1;
                //(a+b)^2 = a^2 + 2*a*b + b^2 其中temp[c[i]]是a,新加的1是b
                //下一次的a要加1
				temp[c[i]] += 1;
                
			}
		}
		return nowans;
	}
	else {
		nowans = nowans + (pre[l + 1][r - 1][maxn] - pre[l + 1][r - 1][minn - 1]);
		for (int i = lift; i <= l * block; ++ i) {
			if (c[i] < minn || c[i] > maxn) continue;
			if (temp[c[i]] == 0) {
				temp[c[i]] = sum[r - 1][c[i]] - sum[l][c[i]];
			}
			nowans = nowans + 2 * temp[c[i]] * 1 + 1 * 1;
			temp[c[i]] ++;
		}
		for (int i = (r - 1) * block + 1; i <= right; ++ i) {
			if (c[i] < minn|| c[i] > maxn) continue;
			if (temp[c[i]] == 0) {
				temp[c[i]] = sum[r - 1][c[i]] - sum[l][c[i]];
			}
			nowans = nowans + 2 * temp[c[i]] * 1 + 1 * 1;
			temp[c[i]] ++;
		}
		return nowans;
	}
}

int main() {
	n = read();
	m = read();
	q = read();
	block = 1000;
	for (int i = 1; i <= n; ++ i) {
		c[i] = read();
		pos[i] = (i - 1) / block + 1;
		sum[pos[i]][c[i]] ++;
	}
	Pretreatment();
	int ans = 0;
	for (int i = 1, l, r, a, b; i <= q; ++ i) {
		l = read(), r = read();
		a = read(), b = read();
		l ^= ans, r ^= ans, a ^= ans, b ^= ans;
		if (l > r) swap(l, r);
		if (a > b) swap(a, b);
		ans = Ask(l, r, a, b);
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2023-05-30 10:39  觉清风  阅读(48)  评论(1编辑  收藏  举报